Diskuse o MVC a můj názor na něj

Tomáš Herceg       04.06.2009       Offtopic, ASP.NET/IIS       17595 zobrazení

Včera jsem se zúčastnil diskuse asp.net MVC Best Practices pořádanou v místní pobočce Microsoftu. Sešlo se tam mnoho zajímavých lidí, nejen ti, kteří dělají v .NETu, ale i lidé, kteří vyvíjejí na jiných platformách, ale používají MVC. Já sám jsem se do diskuse moc nezapojoval, protože můžu srovnávat pouze ASP.NET MVC a ASP.NET WebForms, které tam převážná část diskutujících neznala, ale rád bych tady zareagoval na pár “argumentů” pro MVC, které mi až tolik jako argumenty nepřijdou (ale je to jen proto, že to srovnávám s ASP.NET WebForms). Kdybych ASP.NET nezažil a pracoval dřív jen v PHP, pak bych rozhodně MVC uvítal. Jenže já jsem mezi tím absolvoval WebForms a právě proto se mi MVC (a teď nemyslím jen ASP.NET MVC, ale MVC vzor obecně) nelíbí.

Následující odstavce jsou můj osobní názor na MVC, nenapsal jsem toho v něm tolik, ale myslím, že dost na to, abych si o tom názor udělal. Není to rozhodně špatný přístup architektury aplikací, nicméně v ASP.NET WebForms se mi dělá lépe.

Jen stručně - jak fungují WebForms a jak funguje MVC

ASP.NET WebForms vznikly zhruba před deseti lety a byly svým způsobem revoluční. Oproti klasickému spaghetti kódu se v ASP.NET do stránky daly serverové komponenty (které se zapsaly normálně do HTML stránky) a fungovaly na nich normálním způsobem události, jak je známe třeba z WinForms aplikací. Stav komponent bylo třeba nějak zachovat a někam uložit, vzhledem k tomu, že protokol HTTP je bezstavový, zařídilo se to tak, že celá stránka je formulář a obsahuje mimo jiné skryté pole __VIEWSTATE, které tyto stavové informace drží.

Jednoduše lze oddělit vzhled stránky (markup se serverovými komponentami) a aplikační logika (code behind, který obsahuje obsluhy událostí a samozřejmě mnoho vlastních tříd, který zajištují datovou vrstvu a bussiness logiku; v code behindu by měly být jen obsluhy událostí, manipulace s komponentami a volání funkcí z bussiness vrstvy).

MVC funguje trochu jinak - celá aplikace se dělí na 3 striktně oddělené vrstvy - Model, který obsahuje datovou vrstvu a bussiness logiku (např. zakládání objednávek) se vším všudy, např. validace (jméno objednávky musí být vyplněno). Další vrstvou je Controller, který zpracovává vstupy od uživatele (reaguje na HTTP požadavky a rozhoduje, co se má stát; volá metody z bussiness vrstvy, vytáhne příslušná data z databáze atd.), řeší také oprávnění uživatele, a View, který dostane data od Controlleru a nějakým způsobem je zobrazí (např. vygeneruje HTML). To je velmi stručně řečeno, pokud chcete podrobnější výklad, vřele doporučuji články o MVC od Borka Bernarda, které vyšly na webu http://zdrojak.root.cz.

ASP.NET a tlačítko Zpět

Jeden z argumentů, který včera zazněl, a ke kterému jsem se i vyjadřoval, bylo, že “ASP.NET WebForms aplikace nectí protokol HTTP, že se používá POST místo GETu, že správně nefunguje tlačítko Zpět atd.”

Ano, je pravda, že ASP.NET zachází s HTTP jinak, než ostatní technologie. Pokud je programátor prase a nepozná rozdíl mezi komponentami HyperLink a LinkButton (HyperLink je klasický odkaz na jinou URL, tedy potažmo GET, a LinkButton je odkaz, který pomocí klientského skriptu odesílá formulář, dělá PostBack, potažmo tedy POST), pak se může velmi snadno stát, že i pro operace, pro které se má používat GET, se použije PostBack. Tuhle pitomost dělá co já vím ještě komponenta Calendar, kterou ale stejně nedoporučuji používat, protože generuje strašné HTML.

Stejně tak nekorektní fungování tlačítka Zpět, samozřejmě že v ASP.NET jde napsat aplikace, kde Zpět nebude fungovat správně, ale chce to dost námahy a stane se to akorát lidem, kteří absolutně nechápou, jak HTTP funguje. Tohle prostě není problém ASP.NET WebForms, ale problém programátora. Programovat v ASP.NET tak, abychom správně používali POST a GET nedá žádnou práci navíc, je to naprosto přirozené.

MVC a lepší testování

Obecně si myslím, že většina programátorů v ČR ještě nedospěla k tomu, že kód by měla nějak systematicky testovat. Ano, testujeme všichni tím, že alespoň jednou zkusíme, jestli aplikace jde spustit. U větších aplikací se ale většinou vyplatí strávit čas vytvořením sofistikované sady testů (což mimochodem není nic jednoduchého). “Aplikace v MVC se testují daleko lépe než ostatní aplikace.

Pokud je aplikace zbastlená (tzn. je psaná pomocí spaghetti kódu, nemá pořádnou datovou vrstvu, nebo se píše v ASP.NET a i komplexní logika je v code behindu), nemá stejně smysl testovat a nikdo ji ani testovat nebude. Pokud je to aplikace malá, všeho všudy o deseti stránkách, nemá většinou cenu ani nějakou datovou a business vrstvu dělat (v případě, že víme, že se na aplikaci nebude nic moc nabalovat, pokud ano, je nutné s tím počítat dopředu).

Pokud je aplikace větší a testovat by se měla, tak má stejně nějak vyčleněnou datovou a business vrstvu (model). Ten vypadá víceméně stejně bez ohledu na použitou technologii a testovat se bude také stejně. Pro testování funkčnosti aplikace se používají nějaké automatizované web testy (simulace požadavků a sledování výsledků podle předem daného scénáře), skuteční testeři, kteří aplikaci fyzicky proklikají, případně další způsoby, ale ty jsou také nezávislé na použité technologii a jdou aplikovat prakticky všude.

Co v MVC zbývá? Model otestovaný máme, View také, chybí ještě Controller. Je ten potřeba testovat? Podle mého názoru v drtivé většině případů ne. To, jestli správně funguje autentizace, se dá ošetřit (a také se to tak většinou dělá) spíš pomocí webtestů, a v Controlleru stejně děláme jen to, že zavoláme něco z Modelu, který upraví databázi (což už máme otestované), a pak vytáhneme data a předáme pohledu (což se otestuje webovou částí). Jakákoliv složitější logika nemá stejně v Controlleru co dělat a patří do modelu. Co se tam tedy testuje lépe?

MVC se hodí na všechny typy webových aplikací

Tohle je argument, který se mi nelíbí ani trochu, není ničím podepřen. Pokud má znamenat, že se v MVC dají napsat všechny webové aplikace, pak nezbývá než souhlasit (není ani divu, kdyby MVC nebylo turingovsky úplné, tak by se s ním určitě ani nikdo nezabýval). Problém je v tom, že pořád mám v MVC při programování víc práce (a není to tím, že bych s tím neuměl nebo dělal nějaké koncepční chyby).

Demonstrováno to bylo včera na pěkném příkladu - mám nějakou stránku, na kterou chci přidat komentáře. V Modelu mám vše již nachystané, mám napsanou nějakou komponentu, která komentáře zobrazí.

V ASP.NET WebForms to můžu udělat jednoduše - komponenta prostě sáhne do databáze, vytáhne komentáře a zobrazí je. Není to nic proti ničemu, neporušujeme tím žádný koncept, nemixuji vzhled a logiku dohromady (ve stránce řeknu, co tam má být a jak se to má udělat, o to se vůbec nestarám; v komponentě mám definován vzhled, logika je v modelu a v code behindu jen vytáhnu data a plácnu je do nějakého Repeateru). Vše tedy spočívá jen v tom, že přidám do stránky komponentu.

V MVC musím sáhnout na víc míst - komponentu pro View mám sice již napsanou, ale ona si nemůže sáhnout do modelu (respektive může, ale je to proti architektuře MVC, má to i svá logická opodstatnění, View má být tupá šablona, která jen zobrazuje data, nemá obsahovat žádnou logiku, data má dostat od Controlleru). Musím tedy upravit View (přidat tam na správné místo tu komponentu), a navíc musím upravit Controller, aby předával do View data pro tu komponentu, sama si je vzít nemůže. Je nutné si uvědomit, že Model není databáze, model je soustava tříd, která poskytuje funkce pro práci s daty, samotnou business logiku (třeba evidenci dokumentů, přidávání, odebírání, schvalování, připomínkování atd.). Jak to komunikuje s databází a co je to vlastně za databázi (SQL nebo něco jiného), to už je z hlediska architektury nepodstatné.

Tady je trochu zádrhel - zatímco v ASP.NET z komponenty do modelu sahat můžu, v MVC bych neměl. Já bych správně neměl ani v ASP.NET, ne kvůli konceptu, ale proto, že si tím můžu solidně zavařit a na první pohled není vidět, kolik dotazů do databáze bude a jak to bude s výkonností. Pokud ty komentáře chci zobrazit na třech místech a jedné stránce, tak v ASP.NET si do modelu komponenta sáhne třikrát (když to udělám hloupě; když ne, tak si to model nacacheuje, ale to nemusí být samozřejmost, navíc ne vždy je to takto jednoduché), v MVC jen jednou a všechny “dotazy a žádosti pro data” mám na jednom místě - v Controlleru. Je tedy hned vidět, co stránka bude dělat, je to průhlednější.

To je ale právě to, co mi na tom vadí. Ve WebForms můžu controller jakoby “poskládat z částí” - část je pro komentáře, část je pro články. Pokud budu články zobrazovat na jiné stránce, musím vytahování a předávání šabloně mít na více místech a mám opakující se kód. Komponenty ve WebForms jsou oproti MVC silnější, nahrazují opakující se kód v šabloně i v “controlleru”.

Ano, MVC asi víc programátory vede k tomu, aby psali čistěji. Controller je na jednom místě a není rozcamdaný na části v komponentách. Ve WebForms může neznalý člověk nadělat víc škody (ViewState je sice geniální věc, ale musí se používat tak, aby sloužil a rozhodně ne bezhlavě), v MVC se zase víc nadře a dá to víc práce. Na druhou stranu konkrétně v ASP.NET MVC nejde nějak rozumně zabránit programátorům, aby do View nedávali kód a logiku, která tam nepatří, nejde jim ani pořádně zabránit v tom, aby z View sahali do databáze, což jde proti konceptu a bohužel se to bude tak zneužívat, síla zvyku z PHP je síla zvyku a lidé, kteří dřív bastlili v PHP (a těch je hodně), budou teď bastlit v MVC.

Osobně mám ale raději WebForms. Možná to není tak čisté a v MVC je kontrola nad výstupním kódem, není tam ViewState, ale včerejší diskuse mě nepřesvědčila, spíš utvrdila v tom, že kdo zkusil a ovládl WebForms (tzn. naučil se je pořádně a do hloubky, což není záležitost jednoho týdne), na MVC pravděpodobně nepřejde.

Konkrétně ASP.NET MVC je podle mě krok zpět oproti WebForms, takový návrat k ASP či PHP, nelíbí se mi koncept View jakožto tupé šablony. Právě kvůli tomu jsem utekl od PHP k ASP.NET WebForms a budou muset vymyslet něco mnohem lepšího, aby mě přesvědčili. V každé technologii se dá prasit a v každé technologii se dá psát pořádně.

Odbočka - moje videotutoriály ASP.NET na MSTV.cz a best practices

Pokud sledujete můj videoseriál Začínáme s ASP.NET, který je určen pro lidi, kteří se chtějí s ASP.NET seznámit, nedělejte si iluze, že po jeho shlédnutí budete psát pořádné webové aplikace. ASP.NET se nedá naučit během 20x15 minut, tutoriály jsou k tomu, aby se mohli začátečníci s technologií seznámit a pochopit její principy, které jsou dost odlišné od technologií jiných.

Malé webové aplikace samozřejmě jde klidně psát tak, jak se to v tutoriálech učí, pomocí SqlDataSource atd. Tyto komponenty umožňují napsat jednoduchou stránku za 10 minut a bude to fungovat. Velké aplikace mají samozřejmě datovou a business vrstvu, takže se dají používat stejné komponenty (GridView, Repeater atd.), ale plnit se budou z modelu, ne přímo z databáze. Navíc SqlDataSource jde také dost proti konceptu - v definici vzhledu se definuje i aplikační logika - např. SQL dotazy.

Pokud se ale naučíte, jak funguje SqlDataSource, pochopíte styl a způsob, jakým ASP.NET funguje, pro začátečníky je to ideální. Je to také jediný přístup, který je všude stejný - v každé firmě se velké ASP.NET aplikace píšou jinak, někde mají zakoupené jiné komponenty, model všude vypadá jinak, není žádný společný základ. Navíc nikdo po začátečnících nemůže chtít, aby hned psali profesionálně vyvedené aplikace, důraz se klade na vysvětlení a pochopení principu, protože to je to důležité. Bez této znalosti pak programátoři dělají ty nejhorší chyby.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Diskuse: Diskuse o MVC a můj názor na něj

Díky za pěkný článek. Osobně v ASP .NET programuji několik let a MVC mě moc nenadchlo a nechystám se měnit....

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Diskuse o MVC a můj názor na něj

ahoj, zdravim vsechny.

chtel bych se zeptat jaky mate nazor popr jakou z technologii byste pouzily na masivni front end aplikaci. treba jako basecamp nebo webnode. osobne delam v asp.net asi 5 let a nic me neomezujee. jediny prinos ktery vidim v mvc je cistota vygenerovaneho kodu, a pristupnost pres url prece jenom vetsi nez u asp.net. coz muze but pro verjou aplikaci celkem kriticke. vzhledem k tem vsem robotum. co si o tom myslitem? stejne to nakonec asi padne na asp.net

vojta

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Vygenerovaný kód nikoho nezajímá a pokud v ASP.NET WebForms nepoužijete TreeView a Menu, tak s tím nebudete mít problém.

Na URL můžete použít URL Routing, který je stejný jako v MVC, takže tam taky nevidím rozdíl.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Čistý markup se dá generovat i z WebForms, URL Routing taky není problém. Pokud jde o HODNĚ vytíženou aplikaci, tak bude mít IMHO největší vliv na výkon použitá cachovací strategie. A jestli za tím bude WebForms nebo MVC, to je z hlediska výkonu IMHO jedno (pokud byla otázka myšlena takto).

Augi (nefunguje LiveID login)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Diskuse o MVC a můj názor na něj

Ohledně přidání komentářů - IMHO se v obou srovnávaných technologiích dělají ty samé kroky. Změna v modelu je stejná. Dále se ve WebForms změní markup, v MVC se změní View. Ve WebForms se změní code-behind, v MVC se změní controller.

Ohledně té komponentovosti. Když se srovnává WebForms a MVC, tak se porovnávají de facto dva různé patterny pro UI - MVP a MVC. Zjednodušeně řečeno, MVP je komponentové (tedy aplikace se rozsekává vertikálně), MVC rozsekává aplikaci horizontálně (striktně odděluje šablonu a prezentační logiku).

Proto je IMHO implementace komponent ve WebForms taková přímočařejší a intuitivnější. U ASP.NET MVC je to ještě "zkomplikováno" tím, že je to více close-to-metal framework než WebForms a vyžaduje větší úsilí pro to, aby se v něm dalo efektivně pracovat. Člověk si tedy musí obstarat nebo napsat různé nadstavby nad ASP.NET MVC, které se budou starat o server-side validaci, client-side validaci, DI container, systém pro správu widgetů, zavést správnou hierarchii view-modelů a jejich chování a další drobnosti, které člověku hodně usnadní práci. Samozřejmě si musí také zvyknout na jiný způsob práce než je u WebForms. Když už člověk má tuhle knownledge base, má de facto vlastní framework postavený nad ASP.NET MVC, ve kterém už může sekat weby jako Baťa cvičky ;-)

Zpět ke komponentám - jestli Tě zajímá, jak pěkně vyřešit widgety (komponenty) v ASP.NET MVC, tak v hlavě to už mám a nejpozději během měsíce to snad sepíšu a hodím na blog.

Jo a tomu, aby kóder nepsal nějaký fuj kód (ideálně aby tam nepsal žádný) do view, se dá v ASP.NET MVC zabránit poměrně jednoduše - použít view-engine, který používá nějaký čistě deklarativní jazyk :D

Abych to shrnul, WebForms a MVC vnímám tak, že v každé jde napsat vše - záleží jen na umu člověka. Pokud člověk skvěle ovládá WebForms a necítí se v něm nějak omezen, tak nevidím problém v tom, když u něj zůstane.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Pokud už ve WebForms mám komponentu napsanou, do code-behindu nic nepíšu, vlastnost s identifikací, k čemu se komentáře vzahují, jí přiřadím deklarativně pomocí databindingu.

Co se týče toho ASP.NET MVC, je to možná jen tím, že není tolik vestavných komponent a člověk si všechno musí řešit sám. Samozřejmě že v obou technologiích jde napsat všechno.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jasně - to je to, o čem jsem psal. ASP.NET MVC je closer-to-metal - tak o něm mluví i samotný Microsoft.

Hlavně MVC prostě není stavěné na komponenty, MVP je. Takže je třeba spíše specifikovat, co je komponenta v MVC světě. Existují dva hlavní přístupy.

Může to být buď "RenderAction" (či partial-request), což znamená, že view ví, že tady se má vyrenderovat nějaká komponenta, tak jakoby pošle lokálně request do MVC, který se o rendering postará. Nevýhodou může být zvýšená výpočetní náročnost a také to, že pokud chceme do komponenty něco předat, musíme to dělat poněkud obstruktivně - ale předat nějaké jednoduché nastavení není problém a více většinou nechceme.

Taková komponenta je pak tedy vlastně takovou malou aplikací - má vlastní controller, view-data i view (model beru jako samozřejmost).

Druhým přístupem (IMHO čistčím z hlediska MVC) je to, že view-model obsahuje kolekci nějakých partikulárních view-data pro jednotlivé komponenty (napadá mě analogie s Controls ve WebForms). View pak vyrenderuje komponentu pomocí RenderPartial a předá jí view-data z již zmíněné kolekce. Bindování probíhá deklarativně na úrovni action methods či rovnou celých controllerů pomocí action filters, které se starají o načtení partikulárních view-data. Komponenta v tomto případě se skládá z partial-view (*.ascx), definice view-dat a action filteru, který načítá data z modelu do view-modelu. Autor nějaké superuniverzální komponenty by měl tedy dodávat pouze *.ascx - třída view-modelu je implicitně jeho součástí. Místo partial-view lze ale také použít extensions metody. Pak stačí, když nám autor komponenty dodá statickou třídu obsahující extensions metody pro helpery a máme vystaráno. Takhle teď fungují např. DropdownListy - to jsou jen extensions methods, kterým se předává SelectList (to je ten mnou zmiňovaný partikulární view-data).

No nějak sem se rozepsal...bych mohl udělat CTRL+C CTRL+V a mám blogspot :D

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Ahoj,

pokud jsi včera dával pozor, tak to docela dobře vystihl Karel Minařík. Vše by mělo být v modelu a stejně jako ty zmiňuješ, že do CodeBehing nic psát nebudeš v případě webforms, tak v MVC taktéž nic psát nemusíš. Důležité je, mít vhodně definovaný onen ViewModel (Model).

Poté by ti taktéž stačilo upravit jen View - šablonu. To jakým způsobem bude vypadat šablona již záleží na použitém ViewEngine. Třeba Aleš to představil tak, že by ona šablona mohla mít velice podobný vzhled jako komponenta ve webforms - byť za ní již nestojí onen codebehing, ale je to skutečně jen prezentační prvek.

Tím se nechci nikterak vymezovat vůči jedné implementaci MVC, na úkor implementace jiné webforms (PageController - taktéž MVC princip) http://msdn.microsoft.com/en-us/library/...

Pěkný den

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tomáš to patrně myslí tak, že když máš 10 stránek s 10 Controllery a do všech potřebuješ přidat něco, s čím na začátku nebylo počítáno, budeš muset upravit 10 View a 10 Controllerů, aby ty View měly z čeho brát data (za předpokladu, že to "něco" nejde nějak triviálně získat z reference na Model, kterou už View mají).

V případě Web Forms vyvineš komponentu jednou, otevřeš 10 ASPX stránek a tuto komponentu vložíš.

Snad jsem to tak pochopil dobře. I ten druhý, zdánlivě jednodušší přístup, má ale problémy, jak zmínil Tomáš v článku nebo Vlasta při diskusi, takže jen konstatuji, nehodnotím :)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ups, nějak jsem si nevšiml, že to po mně nechce autora. Takže se podepíšu teď: Borek

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ano, přesně tak to bylo míněno.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ale i v ASP.NET MVC toto lze vyřešit takto pěkně komponentově. Vyvineš komponentu (ve formě extensions metody pro helper) a na deseti stránkách ji desetkrát použiješ (~vložíš).

I ve WebForms pak nějak musíš svázat komponentu s modelem a to v code-behind všech stránek (ať už naklikáním přes binding nebo ručním zápisem). V ASP.NET MVC je to stejné, jen se to děje tam, kde se připravují data, tedy v controlleru. Buď to naprasíš do všech action metod (~napsat to do code-behindu všech stránek) nebo uděláš action filter, který se stará o ládování dat, a ten aplikuješ na dané action metody (tj. přes atributy, tj. deklarativně).

Z hlediska komponentovosti mi tedy přijdou WebForms a MVC nastejno.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ve WebForms svážeš komponentu s modelem pomocí databindingu a jsi schopen to většinou udělat čistě v deklarativní syntaxi, nepotřebuješ na to code-behind. Je fakt, že databinding se nedá použít vždy, ale většinou ano.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Však ano - to jsem také psal (nebo jsem to tak aspoň chtěl yvjádřit). Ale v ASP.NET MVC to lze také udělat čistě deklarativně - pomocí action filterů.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Možná byste si měli domluvit ukázkovou miniaplikaci, která by demonstrovala to, o čem se tady bavíme, a pak ji realizovat ve Web Forms a v MVC.

B.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Chystám se vytvořit takovou ukázkovou miniaplikaci, která bude demonstrovat většinu mně známých best-practices. Součástí ní by mělo být i několik varianty widgetování. To widgetování pravděpodobně ukážu na diskutovaném tématu "přidej komentáře". Ale je otázka, kdy si na to najdu čas :)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Ano, v MVC se tomu myslím obecně říká view helper a ten si klidně může sáhnout do modelu

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback