Příliš mnoho kódu na jednom formuláři   zodpovězená otázka

VB.NET, Architektura, WinForms

Dobrý den,

mám jeden hlavní formulář, na kterém se odehrává vše podstatné. Přidáváním různých jiných procedur a funkcí se kód na tomto jednom formuláři stává nepřehledný. Je ho tam hodně.

Přitom bych mohl kód rozdělit na různé kategorie, aby každá řešila jen ucelenou část. Bylo by to tak mnohem přehlednější.

Jak je toto řešeno u větších projektů?

Např.: rozdělení podle hlavních položek v menuStripItem. (snad se to tak píše)

Díky,

PetrS

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

Co je myšleno tím "rozdělení podle hlavních položek v menuStripItem"?

nahlásit spamnahlásit spam -12 / 12 odpovědětodpovědět

Já jsem to pochopil tak, že v hlavním formu má autor 'složité' respektive obsáhlé menu a každou jeho větev by rád měl někde samostatně. tak jsem to alespoň pobral, já jsem to řešil pomocí regionů, ale je fakt. že pokud je na formuláři rozsáhlé menu a k tomu například několik Toolbaru s tlacitky tak se fakt kod stává trochu nepřehledný, jak uvádím já jsem se to snažil dělit do regionů, ale nechám se rád poučit pokud je něcho efektivnějšího

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

menuStripItem byl pouze příklad. Například kdybych si chtěl vyrobit svůj vlastní prohlížeč, tak když tu koukám na menuStrip tak tam je:

Soubor, úpravy, Zobrazení....

což je hodně položek. Nevěřím, že všechen kód je na jednom místě.

Bohužel neznám Visual Studio, tak nevím jestli to tam s organizací kódu není o něco lepší.

PetrS

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

Mějte v hlavním formuláři jen minimum kódu. Všechen funkční kód umístěte do pomocných tříd rozdělených podle kateogorií.

Obecně doporučuji vytvořit tzv. controller třídu, která se stará o logiku hlavního formuláře. Například formulář FormMain a k němu třída FormMainController, která bude dostupná přes vlastnost ve formuláři. Vy pak už je po klepnutí na položku menuStripItem vyvoláte například jen Controller.UdelejAkciPoKlepnutiNaNeco(). To slovo Controller může být právě vlastnost odkazující na instanci FormMainController. A uvnitř controlleru už můžete dále volat příslušné třídy objektového návrhu vaší aplikace.

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

To co jsem popsal je vlastně návrhový vzor (nebo chcete-li softwarová architektura) Model-View-Presenter http://en.wikipedia.org/wiki/Model-view-...

Sám ho používám i v komerčních aplikacích, doporučuji používat také.

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

To mi připadá jako naprostá, zbytečně komplikující pitomost. Co si tím pomůžete? Výsledek bude pouze přesunutí kódu z formuláře do jiné třídy, přičemž ve formuláři bude muset být stejně mraky handlerů pro všechny ovládací prvky. Neříkám rvát všechno do formuláře, business objekty patří jinam, ale v tom vašem řešení skutečně nevidím nic pozitivního.

nahlásit spamnahlásit spam -14 / 14 odpovědětodpovědět

Takže rozvrstvení aplikace je zbytečné? Nebo spíš jedna vrstva navíc je zákonitě zbytečnost? Neříkám, že se hodí vždy, ale u větších projektů jsem jednoznačně pro. Zvlášť tady, kdy definujete vlastně funkce celé aplikace - hlavního okna - není správné je mít definované v hlavní třídě formuláře.

Toto je běžně používaná architektura, která přináší řadu výhod. Bez tohoto rozdělení vlastně cpete aplikační logiku do zobrazovací vrstvy. Co když pak chcete nabídnout funkce formuláře v rámci jiného formuláře nebo například webové stránky? Buď zkopírujete kód ze všech handlerů a procedur ve formuláři, které mohou být vázené na konkrétní způsob reprezentace dat (odkazy na tlačítka atp.) a nebo použijete třídu controlleru, která všechny tyto funkce nabídne bez nutnosti znát, že píšeme formulář, či webovou stránku. Získáte tak ucelené akce aplikační logiky, které je nevhodné cpát do BO, protože uvažují nad konkrétním způsobem práce s business vrstvou, které jiná část aplikace nevyužije a jsou pro ni zbytečné.

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

Jenže ve většině případů je funkčnost formulářů natolik odlišná, že univerzální řešení nelze vytvořit a potom je celý MVP model zcela k ničemu. Webové aplikace nedělám, tam nevím.

V projektech kde je stopadesát podobných formulářů zobrazujících stejná data by to určité kouzlo mělo.

nahlásit spamnahlásit spam -13 / 13 odpovědětodpovědět

Ono to má kouzlo i při jednom formuláři. V controlleru máte čistě funkční kód aplikační logiky a ve formuláři pak jen říkáte, co se stane při té a které události a do čeho zobrazit data vrácená controllerem. Zas o tolik kódu navíc to není.

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

Při vší úctě při jednom formuláři je to naprostá zhovadělost a neúměrná práce navíc.

nahlásit spamnahlásit spam -13 / 13 odpovědětodpovědět

Zvlášť při jednom formuláři ve kterém běží celá aplikace je to výborné řešení.

1. není to tolik psaní navíc - definice třídy a volání metod této třídy je jen o pár řádků kódu navíc na celém projektu - stejně tam budete mít obecné metody (pokud nebudete vše cpát do handlerů) - tomu říkáte neúměrná práce navíc? Nikdo neříká, že máte vše dělat abstraktně proti interfacům a připravit aplikaci na změnu prezenční vrstvy se zachováním aplikační logiky.

2. controllerů můžete mít víc a větší množství akcí tak vhodně dělit do ucelených kusů

3. pokud máte další formuláře v rámci hlavního formuláře, či komponenty, je vhodné jim předávat controller a oni pak mohou unifikovaným způsobem provádět různé obecné akce

Přístup se vám líbit může i nemusí. Rozhodně si ale stojím za tím, že to není zhovadělost.

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

1. Vytvářet za každou cenu podobné věci když je jasné že jejich znovupoužitelnost bude nulová a přínos žádný je práce navíc.

2. Čím více takových tříd a komplexnější členění, tím více narůstá složitost projektu a vzniká riziko chyb, testování je složitější, údržba kódu náročnější.

3. Jak už jsem psal je funkčnost jednotlivých formulářů většinou tak rozdílná, že univerzální řešení nelze udělat a specifické řešení pro každý formulář pak spěje k bodu 2.

nahlásit spamnahlásit spam -13 / 13 odpovědětodpovědět

1. Znovupoužitelnost nulová nebude. To je také jeden z hlavních účelů tohoto návrhu. To, že ji nevyužijete je věc druhá. Důležité je, že to nezabere moc práce něco takového napsat. V případě potřeby je ale 100x jednoduší použít existující controller než tahat kód z formuláře a vkládat ho do obecné třídy nebo snad znovu kopírovat.

2. To je otázka pohledu. Více vrstev může být někdy zpřehlednění, někdy naopak a často je to subjektivní věc.

3. Většinou ano. Ale pokud pak napíšete nový formulář, který má být funkčně podobný jinému, tak to oceníte. To je ale už něco, o čem nemá cenu diskutovat, je to jen dodatečná výhoda, která se občas může hodit, není to důvod proč MVP používat.

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

Když je něco specifické, jednoúčelové a je již od začátku jasné, že se to nebude používat jinde tak snad nemá cenu to implementovat pomocí univerzálních postupů, na tom se snad shodneme ne? Psát controller který bude používat jeden jediný formulář je nesmysl, skutečně to nepřináší nic pozitivního. Jinak by mě zajímal i názor ostatních kteří se již zabývali podobnou problematikou.

nahlásit spamnahlásit spam -10 / 10 odpovědětodpovědět

Jenže tady jde o možnost znovupoužitelnosti a zpřehlednění oddělením kódu od sebe. Také by mě zajímalo, jak na to nahlíží ostatní.

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

Pokud se třeba obsluhy událostí dají rozdělit do menších skupin, pak je vhodné rozdělit kód z formuláře do více parciálních tříd.

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

Nemluvíme ale o parciálních třídách. Snažím se obhájit MVP návrhový vzor - tedy obecně řečeno oddělení vzhledu (společně s obsluhou událostí), aplikační logiky a BO.

Ale ano, pokud chce mít tazatel vše v jednom formuláři, pak regiony a parciální třídy mohou pomoci. Stejně si ale stojím 100% za použití vzoru model-view-presenter, používám ho již dlouho a značně mi usnadňuje práci.

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

Některé návrhové vzory (většinou ty, které začínají MV) jsou dost odtržené od reality a přestože se pro praktický vývoj sice používají, dá se to řešit i bez nich a mnohdy daleko lépe - s měnším množstvím kódu.

Ano, aplikace má být dělená na vrstvy, ale v mnoha případech stačí vrstvy dvě, ta třetí je tam jaksi nadbytečná. Zvláště pak u menších projektů.

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

Přesně tak a hlavně se nemusí zbytečně řešit interakce mezi jednotlivými částmi MVP.

nahlásit spamnahlásit spam -7 / 7 odpovědětodpovědět

To je zase otázka přístupu. Mě by zajímalo, proč myslíš a podle jakých zkušenostech sis udělal názor, že MV* vzory jsou odtržené od reality? Chápu, že v tobě může například MVC vyvolávat rozporuplné pocity, když bereme v potaz, že jsi si zvyknul na naprosto jiný přístup s ASP.NET WebForms.

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

Ne, to není o tom, že bych se naučil jednu věc a už nikdy nechtěl nic jiného.

Důvodů pro to je celá řada - to hlavní, co mě štve, je ta mezivrstva Controller - nedělá v podstatě nic jiného než že přetahuje data z Modelu do View a opačně, když to trochu zjednoduším. K ničemu jinému není - validace a řešení věcí jako je oprávnění se mají dělat v modelu (protože ten může používat časem třba i těžký klient atd.), generování výstupů je ve View. Controller je v podstatě zbytečný kód, který jenom přenáší data z jednoho místa na druhé.

V ASP.NET WebForms je to jasné - vzhled je vzhled, datovou vrstvu má člověk tak jako tak a analogie controllerů jsou EventHandlery. Ale ty už opravdu dělají jenom to, co se dělat mají, nestarají se o vytažení dat a přesouvání z místa na místo (od toho jsou třeba DataSources, které si nastavím deklarativně; nebo to mají dělat komponenty samotné, abych to neměl v každém Controlleru, kde tu komponentu používám).

Ano, i v MVC se dají psát a dělat komponenty a ty frameworky to podporují, na druhou stranu ty komponenty jsou pořád o dost slabší než v ASP.NET WebForms. V praxi je MVC vždycky víc psaní, víc opakujících se patternů v kódu a pomalejší vývoj. Ten návrhový vzor za to nemůže úplně, ale z části ano.

Ale to jsme tak trochu odbočili.

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

Pokud jde o MVC, já souhlasím, také mám raději WebForms. Tohle je ale trochu něco jiného. MVP je proti MVC přeci jenom trochu přátelštější k běžnému návrhu právě událostmi v pohledu, což je formulář. To znamená, že jediná změna je odrtžení funkčních bloků do controlleru (respektive presenteru).

Na psaní v MVC jsem si nezvykl dodnes. A to v něm dělám relativně často. Ale na používání presenterů při návrhu formulářů s hlubší aplikační logikou jsem si zvykl velmi rychle a teď již na ně nedám dopustit. Měl jsem ale štěstí, že jsem do nich spadnul už na větším projektu a tak jsem měl šanci vidět, jak to vše má fungovat na něčem rozsáhlejším. A neskutečně mi to usnadnilo práci a orientaci v kódu. A to nemluvím o dalších drobných radostech právě s rozšiřitelností.

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

Moc děkuji za odpověď.

Bohužel nejsem na té úrovni, abych s Vámi mohl polemizovat o použití té které metody. Mám-li být upřímný, toto fórum považuji za primární zdroj nových informací a svůj projekt jako učební prostředek bez ohledu na to, zda je to pro konkrétní případ výhodné nebo ne.

Co je ale podstatné, tak to je znalost takové možnosti, abych si příště mohl vybrat,co pro konkrétní případ použít.

Bez toho bych stále programoval pomocí for a if. Taky to jde...

PetrS

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

Trochu se nám to zvrhlo.

Zpět k původnímu dotazu - pokud máte ve formuláři moc kódu, zkuste vymyslet, jestli by se některé jeho části nedaly vyčlenit do samostatné třídy. Možná tam máte nějaké kusy kódu, které jsou velmi podobné a daly by se z nich udělat metody, které by se volaly s různými parametry.

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

Moc tomu nerozumím. Měl jsem za to, že třídy jsou použity pouze pokud obsahují nějaká data.

Samozřejmě si umím představit třídu, která v sobě má pouze metody měnící vstup na nějaký výstup, ale vůbec si nejsem jistý jestli to neodporuje nějakému OOP pravidlu.

Navíc pro třídu pak musím stále definovat její instanci.

Některé metody (funkce), jsem nasekal do MODULU a ty metody potom volám bez vytváření instancí. Opět nevím jestli je to správný postup.

PetrS

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

Přístup máte správný, proto zkusím vysvětlil, proč se používají třídy takto.

Jde o to, že máte například třídu definující přístup k databázi. Tu ale nechcete využívat přímo z formuláře. Proto vytvoříte další třídu, která uvnitř sebe vytvoří instanci právě datové třídy a pak její funkce přistupují právě k metodám této datové třídy. Takže navenek pracujete s novým objektem, který nabízí požadované funkce a přitom vůbec nemusíte komunikovat s datovou vrstvou. Navíc funkce nové třídy mohou být už konkrétnější přímo pro potřeby aplikace. Ve složitějších projektech máte takových "vrstev" více a to značně ulehčuje hledání chyb díky menším kusům kódu rozdělených do více tříd a zároveň lepší rozšiřitelnost a případné úpravy.

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

Tak to bych se zase hádal. Hledání chyb to rozhodně neusnadňuje, buď se bude hledat chyba v jednom větším celku nebo v milionu malých kousků což je podle mě daleko složitější. Krokovat se bude tak jako tak. Co se týče rozšiřitelnosti tak to má význam pouze v případě, že je daná věc využívána na více místech.

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

To snad nemyslíte vážně. Sazmořejmně že procházení vrstvama při krokování je pomalejší, protože se musíme vnořovat přes třídy hlouběji a hlouběji. Ale z hlediska obecné udržitelnosti a například implementace testů je rozdělení do elementárních celků reprezentujícíh úkony jednotlivých vrstev naprosto základní věc. Pokud máte jasně definováno, že datová vrstva má vracet seznam zákazníků podle určitého filtru, tak lze velmi snadno otestovat zda: přicházejí odpovídající parametry vrstvě, zda vrstva uvnitř provede patřičný úkon a zda správně vrací výsledek. Druhý naprosto příklad je výskyt chyby - víte kde vznikla, ale nevíte proč - při vícevrstvém návrhu snadno odhalíte, zda chyba pochází v podobě chybných parametrů z vyšší vrstvy, implementací aktuální vrstvy, či výsledkem z nižší vrstvy.

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

Důležité je zkontrolovat aplikaci jako celek, než kontrolovat zda-li se něco správně načte v určité části. Pokud se to totiž načte v určité části správně, ale z nějakého důvodu nezobrazí v uživatelském rozhraní (nebo naopak se data z UI nedostanou do business objektu), potom jsou vám tyto hovadské testy vrstev naprosto k ničemu. A jak jistě víte testování uživatelského rozhraní je velmi komplikovaná věc kterou provádějí buď testeři (funkčním testováním aplikace), nebo jsou na to specializované aplikace. K tomu výskytu chyby - je uplně jedno jestli je to rozdělené do vrstev nebo ne, podstatné je se dopracovat k příčině a k tomu vám rozdělení do vrstev rozhodně nepomůže (jinak řečeno mě nezajmá kde vznikla chyba ale proč vznikla).

nahlásit spamnahlásit spam -6 / 6 odpovědětodpovědět

K celkovému testování slouží integrační testy a právě díky použití vrstev je možné odtestovat funkčnost až těsně pod uživatelské rozhraní, jehož testování je mnohem průhlednější, když lze testy podchytit dodávku "špatných" dat z nižších vrstev. Mám pocit, že popíráte naprosto základní principy vývoje větších aplikací. Kontrola úprav a testování je prakticky nemožné bez "hovadských" testů a kvalitního návrhu vrstev. Je snad zcela zřetelné, že pokud máte rozdělenou nějakou funkci například do 4 vrstev a něco přestane fungovat, tak už jen pomocí dat, které si vrstvy předávají, máte šanci zjistit v jaké vrstvě chyba nastala a tak ji snadno lokalizovat.

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

No a já mám zase pocit, že se snažíte za všech okolností protlačit obecné hovadiny i tam, kde to absolutně postrádá smysl a jste odtržen od reality. Integrační testy jsou dobré pro udržení integrity aplikace, rozhodně ale ne pro funkční testování aplikace. To je přesně ten případ, který jsem popisoval - business vrstvu napojíte na nějaké mock objekty, které budou předstírat uživatelské rozhraní nebo vstupy a budete kontrolovat výstupy a s úsměvem na tváři od toho odejdete jako že je otestováno. Takovou ubohost ovšem ani nemá cenu dělat, protože ke skutečnému provozu aplikace to má mrtě daleko. Proto je to dobré jen k udržení integrity projektu - když tam někdo něco dodělá, tak podobnými testy se dá lehce zjistit, jestli se tím nerozesralo něco jiného. Kromě toho psaní samotných testů mnohdy zabere více času než samotný vývoj a proto je třeba zvážit, zda-li se to vyplatí. A mluvím samozřejmě o velkých projektech. A co se týče těch vrstev, tak je to zase to samé omílání předchozího. Nezáleží na tom kde chyba nastala (navíc ještě zkoumat v jaké vrstvě bylo co předáno a podobné zdržující nesmysly), ale co jí způsobilo.

nahlásit spamnahlásit spam -6 / 6 odpovědětodpovědět

Začínáme se dostávat někam úplně jinam a navíc se neshodneme ani v elementárních případech. Pravděpodobně používáte při vývoji úplně jiné postupy a úplně jiné architektury. To co označujete jako ubohost a nesmysly se mi nespočetněkrát osvědčilo a usnadnilo mi práci. A to si rozhodně nemyslím, že by mé aplikace byly nerozšířitelné, zbytečně roztahané, nepřehledné a pomalé (což by musela být pravda, kdyby váš názor na výše uvedené obecně známe a používané postupy byl pravdou).

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

Vámi uváděné postupy jsem si již několikrát v praxi vyzkoušel a z mnoha důvodů se osvědčily jako nepoužitelné, jinak bych to samozřejmě netvrdil. Uznávám některé testovací metodiky a mnoho použitelných návrhových vzorů, ale rozhodně se je nesnažím používat všude a za každou cenu pouze z důvodu, že jsou to obecně uznávané postupy.

nahlásit spamnahlásit spam -6 / 6 odpovědětodpovědět

To jsme na tom stejně. Používám je úspěšně již několik let na komerčních projektech, kde je třeba jak rozšiřitelnosti, spolehlivosti, tak i co nejkratší přijatelné doby vývoje. Pravděpodobně jsou tedy nároky a podstata projektů na kterých pracujeme úplně jiné. Zároveň jsem ale nikdy neříkal, že je nutné je používat vždy a všude.

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

Modul je statická třída (třída která existuje pouze v jediné instanci vytvořené automaticky) přístupná odevšud (pokud není deklarovaná jako Private) a toto právě odporuje jednomu z pravidel OOP - zapouzdřenost.

nahlásit spamnahlásit spam -2 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • 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