Je to samozřejmě extrém, ale ve spoustě věcí mají pravdu. Bloatu je všude kolem mraky, je potřeba vyvažovat opakem z druhé strany. A ta striktní pravidla v konečném efektu dávají smysl, boj s bloatem je bez nich asi nereálný.
Kdyby se každý vývojář od nich naučil třeba jen to, že je nutné se nad těmito otázkami zamýšlet a že jejich kód bude muset někdo další po nich udržovat, už jen v tom by jejich úsilí mělo přínos.
> Návrhové vzory byly zavedeny právě z těchto důvodů.
To ovsem nic nemeni na tom, ze jako reseni je to naprosty omyl. Spravne reseni by bylo ony "navrhove vzory" zahrnout do abstrakci prislusneho jazyka - jako to treba dela Common Lisp, a proto v nem neco jako "navrhove vzory" neexistuji.
+1
Je neuvěřitelné co se kolem Design Patterns naakumulovalo za cargo cult, že i po dvaceti letech se stále můžeme dočkat perel typu "nauč se návrhové vzory" nebo "v Lispu návrhové vzory neexistují". Přitom si stačí přečíst předmluvu od GoF, na Amazonu je k dispozici zdarma.
No, konkretni odpoved by asi zavisela od problemu a od jazyka, ale vetsinou asi.. zadnou?
Pokud chcete napojit neco nekam, kde se ceka neco jineho, pak to musite napsat tak jako tak. Fakt, ze to pojmenujete vznosne "adapter", na citelnosti nijak nepomaha (a tedy to neni vhodny priklad pro vase tvrzeni).
Adapter je navic dost specificky vzor pro jazyky typu Java (staticky typovane OOP). Ale odpovidajici problem da resit mnoha ruznymi zpusoby, v zavislosti na jazyku.
Vic informaci o tom, na co narazim, tady: http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatures
Aha, už asi vím, kde je problém. Já chápu design patterns z větší části jako záležitost architektury programu. Proto se také jmenují DESIGN patterns, ne třeba LANGUAGE patterns. Konkrétní implementace patternu v konkrétním jazyce je podružná věc.
Takže když vidím v kódu (poznámce, jménu třídy), že je něco Adaptér nebo Singleton (nebo jiný pattern), tak vím, jak to funguje, co to má dělat bez toho, že bych to musel hlouběji zkoumat. A o to jde.
> Niektore vzory nemaju velmi siroke uplatnenie.
To ani mít nemusí. Stačí když se často vyskytují v některých specifických oblastech. Víc než na jazyce závisejí použité vzory na tom, co se zrovna řeší. Třeba Adaptér je skoro k ničemu někomu, kdo může věci přepisovat podle libosti. Mají o něj díky tomu přijít lidé, kteří musí udržovat binární kompatibilitu třeba půl roku zpátky? A o tom, jestli je nějaké uplatnění dost široké, nebo ne, bych se opravdu nerad s někým hádal.
Jinak receno, je to pro tebe proste terminologie. Ale ta terminologie ma jiste predpoklady, napr. O~OP. Kdyz budu mit v Lispu multi~metodu na dvou objektech, mohu tam napsat, ze je to Visi~tor, nebo je to hlo~upost? Pritom arch~itekturalne je to stejne.
A pokud to tedy beres jako zalezitost architektury a ne implementace, jak to zlepsuje citelnost pro~gramu (to bylo tve puvodni tvrz~eni)? Mozna to zlepsuje citelnost nejakeho popisu archite~ktury (i kdyz i tam o tom mam pochybnosti, jelikoz je to v podstate termino~logie navic), ale programu samotneho?
T.o z.á.l.e.ž.í, j.e.s.t.l.i tu m.e.t.o.d.u p.o.u.ž.í.v.á.š jako V.i.s.i.t.o.r nebo ne.
Č.i.t.e.l.n.o.s.t p.r.o.g.r.a.m.u to z.l.e.p.š.u.j.e jak jsem psal výše - pokud ze jména t.ř.í.d.y nebo p.o.z.n.á.m.k.y v.y.p.l.ý.v.á DP, tak rovnou vím, co ta třída z.h.r.u.b.a dělá, jaké bude mít č.á.s.t.i./.m.e.t.o.d.y atp. A n.e.m.u.s.í.m ji r.o.z.p.l.é.t.a.t úplně od z.á.k.l.a.d.u.
Ten radoby-antispam-blacklist me taky stve, obtezoval me uz vicekrat pri zcela korektnich prispevcich.
Vyzkousime, zda je ucinny na skutecne spamy:
Kupte si viagru zvetsi se vam penis budete mit pero jako kladu, stoji u nas pouze 10,000$ a poslete nam zalohu 500$ na konto Umba Lumba, 120 00 Nigerie.
A co třeba továrna nebo obecně třída, v jejíž instanci si něco připravím, inicializuji a z které pak vycházejí další objekty? A je to navržené tak, že ten první udělá při inicializaci co nejvíc práce a metodu na generování objektů lze volat z různých vláken. A ten druhý objekt už používám jen v rámci jednoho vlákna, takže se v něm nemusí řešit žádná synchronizace a je to díky tomu rychlejší a spolehlivější.
1) je to terminologie – každý obor vytváří různé kategorizace, třídí věci do škatulek a pak nad nimi rozjímá :-) SW inženýrství není výjimkou.
2) je to sbírka ověřených nebo alespoň vyzkoušených postupů, ze které se programátor může inspirovat, a může si přečíst o výhodách a nevýhodách jednotlivých vzorů – a podle toho se lépe rozhodnout, jaký postup pro řešení daného problému použít. Stejně tak existují návrhové vzory pro relační databáze nebo třeba sbírky algoritmů… Nadpis v nějaké knížce spíš bude „Tovární metoda“ než „tato funkce vraci novou instanci objektu x“ :-)
Ano, to jsem uz napsal, ze je to terminologie, ale jeji prinos je podle me (casto) diskutabilni. Treba v pripade tovarny si to myslim celkem urcite.
Nicmene takova terminologie jeste sama o sobe nezprehlednuje zapis programu, mozna zprehlednuje komentare, ale to je tak cele. Takze i kdybych uznal, ze je to uzitecna terminologie, porad zbyva dolozit puvodni tvrzeni z tohoto vlakna.
Tady je to spis historicke, ale zrovna "prirozena cisla" zase tak uzitecny pojem nejsou, pokud uvazime, ze v (matematicke) praxi se pouzivaji asi tak stejne casto (a mozna i casteji, specialne v CS) nezaporna cela cisla jako pozitivni cela cisla. Spis by se v praxi hodilo nejake kratke oznaceni pro "mnozinu nezapornych celych cisel mensich nez N".
> pokud uvazime, ze v (matematicke) praxi se pouzivaji asi tak stejne casto (a mozna i casteji, specialne v CS) nezaporna cela cisla jako pozitivni cela cisla.
Definice prirozenych cisel casto zahrnuje nulu.
> Spis by se v praxi hodilo nejake kratke oznaceni pro "mnozinu nezapornych celych cisel mensich nez N".
Pro to se obcas pouziva primo cislo N (tedy to cislo, ktere je mezi), v souladu s definici z teorie mnozin, ktera konstruuje prirozena cisla jako mnoziny vsech jejich predchudcu. Ale IMHO to je matouci znacneni.
Nezbývá, než souhlasit. Vyznávám Occamovu břitvu i Euxupéryho tvrzení "Dokonalosti se nedosahuje tehdy, když už se nedá nic přidat, ale tehdy, když už se nedá nic odebrat". ale tohle je fakt moc i na mě.
Návrhový vzor se nesmí přeceňovat, ale pro zjednodušení návrhu a údržby je fajn. I dokumentace je o řád jednodušší, když se tam napíše "... byl využit návrhový vzor x" než popis vlastního řešení.
Navíc averzi k C++ taky nechápu. Jazyk by neměl být cíl, ale prostředek, jak něčeho dosáhnout. Když budu mít v okně pět tlačítek, mám několik možností, jak to udělat:
1) Napsat si kód pro jedno tlačítko a s pomocí Ctrl-Cizí + Ctrl-Vlastní vytvořit v kódu jeho klony s tím, že u všech klonů změním názvy dotčených funkcí, jejich volání, referuju na jinou bandu proměnných atd. Takhle pohnojený pole pro růst chyb se málo kdy vidí a takový program těžko bude dělat něco dobře. Nehledě na to, jaký má člověk čichový vjem z pole, na který právě zemědělec vyšplíchá cisternu močůvky. Takže tudy ne.
2) Napsání kódu pro tlačítko, kde je funkcionalita popsaná abstraktně a zpracovává se nějaká struktra, co popisuje chování, pozici, nápis, callbacky a předává se každé funkci. Takže si musí hlídat nejenom data, ale i volání funkcí a jejich parametry a je zase po kotníky v mrvě.
3) Jít na to objektově, vytvořit třídu pro tlačítko a do okna nasázet jejich instance. V podstatě je to jako řešení 2, ale s tím rozdílem, že nemusí ručně definovat strukturu pro funkce a jejich volání, strukturu pro data, inicializace, uvolňování paměti,... Všechno to splácá kompilátor (ono vlastně C++ byl prekompilátor, co automaticky přepisoval konstrukce do C a redukoval tak chyyby a zbytečnou práci). Takže vytvoření instance a její inicializace smrdí chybama o poznání míň. Navíc se to mnohem víc blíží stavu, kdy programátor myslí na řešený problém a ne na to, jak obejít omezení prostředí a je větššance, že najde efektivní řešení.
A to nemluvím o dědičnosti, kde při pokusech o OOP v C jedna struktura odkazuje na druhou, musí se hlídat typ a pořadí dat ve strukturách potomků, nefunguje automatická kontrola, která by varovala před jiným návratovým typem... Neexistenci výjimek a zaplevelení kódu pomocí GoTo... Neexistenci výjimek a zabrání návratové hodnoty funkcí chybovým kódm, jeho neustálým testováním a vracením hodnot pomocí pointerů, který můžou "uletět" a něco přepsat...
V mým případě Occamova břitva bere duplicity v kódu i management spojený se správou dat. Zůstane ta třída v C a ještě osekaná o duplicitní funkcionalitu, kterou může dělat předek...
Takže tohle hnutí beru za pochybnou sektu, která považuje C za posvátný a odmítá jeho znesvěcení ať už objektovou nástavbou, nebo použitím standardních dokumentovaných postupů a staví se dokonce i proti ukládání dat v CSV.
Z 99% souhlas.
Tedy az na "zapleveleni kodu pomoci GoTo" - dobre pouzite goto muze C kod
velmi vyrazne procistit a z prehlednit - typicke pouziti, kdy je IMHO goto v C
neprekonatelne je treba takovyto "construktor":
struct SomeStruct *some_struct_new(..., int *errcode)
{
int ret = OK;
struct AStruct *a = NULL;
struct BStruct *b = NULL;
struct XStruct *x = NULL;
struct SomeStruct *self = NULL;
a = a_struct_new(...);
if (a == NULL) {
*errorcode = ERROR_A;
goto error;
}
...
b = b_struct_new(a, ...);
if (b == NULL) {
*errorcode = ERROR_B;
goto error;
}
...
x = some_struct_new(a, b, ...);
if (x == NULL) {
*errorcode = ERROR_X;
goto error;
}
...
self = (struct SomeStruct*)malloc(sizeof(struct SomeStruct));
if (self == NULL) {
*errorcode = ERROR_MALLOC;
goto error;
}
...
exit:
return self;
error:
if (x != NULL) {
some_struct_destroy(x);
x = NULL;
}
if (b != NULL) {
some_struct_destroy(b);
}
if (a != NULL) {
some_struct_destroy(a);
}
self = NULL;
goto exit;
}
Zde mam jenom jeden return, mam oddelenou "cleanup" cast, kde mam i zarucenou
spravnou posloupnost ruseni struktur a hlavne je "hlavni kod" minimalne
zatizen obsluhou chyby.
Pozor, vyjimky maji vyrazne lepsi uplatneni pokud je potreba predat vyjimku z vnitrni funkce ven. Tam kde nelze ven vratit vyjimku mi konstrukce s goto pripada o chlup lepsi, protoze clovek nemusi premyslet nad tim kde a jak se vyjimka konstruuje (je to objekt) a kde destruuje.
Vyse uvedeny kod je spise priklad pro destruktor nez pro vyjimku.
Jenomže stačí, když se najde nedouk (takových v téhle sektě bude plno, když nepobrali ani princip OOP) a hodí GOTO ven z funkce, zůstane rozhozený zásobník... Je fajn, že vy znáte meze kde to použít, ale podle toho se nedá zobecňovat.
A stejně to pak vede k obsazení návratové hodnoty a jednoho parametru funkce ukazatelem na instanci, výjimka a OOP je čistší. Jejich posvátný C už patří jenom do embedded světa a psát v něm na PC - s výjimkou školních projektů, částí systému a unit testů embedded software - je pomalu ostuda.
Samozrejme, temer kazdy jazykovy konstrukt se da zneuzit. Jen jsem chtel ukazat, ze absolutni slepe odsuzovani "goto" je zcestne. Navic podle me je v C mnohem vice mnohem horsich veci, ktere mohou zpusobit (a take zpusobuji) velke problemy (pointery, alokace pameti, ..)
A protoze jsou systemy, ktere jsou psany v C, a je VYZADOVANO aby zustaly v C, tak zadne vyjimky pouzit nelze.
90% "programatoru" vzivote nevidelo co z toho jejich kodu ve finale vyleze ... a velmi casto tyto "prasarny" vedou k vyrazne rychlejsimu/mensimu/... vysledku. OOP je pak velmi vyzdvihovany princip, ktery je casto naprosto nanic a jeho pouziti vede naopak k naprosto neprehlednemu a nespravovatelnemu vytvoru.
Podobne jsme na to s vyjimkama a dalsima "ficurama" ... nic nepotesi vic, nez kdyz na me nekde vyskoci "neosetrena vyjimka" + nejaky kilometrovy cosi ... proto, ze ten mastic co to napsal proste neresi, co funkci preda, ale proste ji zavola, klidne se stringem misto cisla na vstupu ...
Ale to co rikate plati o uplne vsude. Jestli Vam dobre rozumim, rikate v podstate toto:
A ja pak rikam:
Reaguju predevsim na to, ze programator nemusi vubec tusit jak vypada OOP a presto muze psat velmi dobry a kvalitni kod, a to i presto, ze pouziva tzv "prasacke" postupy (trebas goto ven z funkce), proste proto, ze vi co to dela a pocita s tim.
Ostatne procesor/assambler stejne nezna nic jinyho nez skok na nejakou adresu. Takze z libovolnyho kodu nakonec vyleze cosi plne "goto".
Nemluve o tom, ze se dycinky rozesmeju, kdyz nekdo pise hello world (asi bych mel spis plakat) a potrebuje na to 5MB binarku a samozrejme si na to nejdriv vyrobi objekt ... a aby mu to vubec bezelo, je treba jeste nainstalovat 500MB .NET
Kromě JMP + JMP existuje i CALL + RET! A ta druhá dvojice, narozdíl od první, nechá něco v zásobníku! Navíc je většinou limitovaný počet registrů, takže se při volání funkce data z volající naperou do zásobníku.
Takže o někom, kdo použije GOTO z funkce i o jeho programech si myslím svoje, zvlášť pokud to obhajuje, že "stejně je to interně JMP". Nechat bordel v zásobníku je zhovadilost a po čase nutně vede k stack overflow se vším, co z toho plyne. Stabilitou aplikace počínaje, pověstí programátora pokračujíce a týdny hledání příčiny konče (protože aby to ten vůl našel, musí se napřed naučit, jak to vlastně celý funguje a to za večer nedá).
To závisí na architektuře. Například na IBMských mainframech analogie CALL uloží do daného registru adresu následující instrukce a kus PSW a analogie RET obnoví z daného registru ten kus PSW a skočí na adresu v něm. To mimochodem znamená, že volaná rutina musím vědět, jak byla volaná (usus je, pokud si pamatuju, to předávat v registru 13, ale nic člověka nenutí to tak udělat a jsou situace, kdy to ani udělat nejde). Co pak volaná rutina s tím registrem udělá, je její věc, ale žádný zásobník tam nehledejte.
A jen tak mimochodem, v C je label lokální identifikátor viditelný jen v dané funkci, takže skok do jiné funkce přes goto udělat nelze (narozdíl třeba od Pascalu).
> Nechat bordel v zásobníku je zhovadilost a po čase nutně vede k stack overflow se vším, co z toho plyne.
Delals nekdy neco v asm? Nebo ses aspon dival co ti vygeneruje prekladac?
Treba na x86 se to dela tak ze si pri vstupu do funkce zalohujes aktualni hodnotu registru SP (stack pointer) do registru BP. Provedes kod funkce. A pred returnem SP zase obnovis. Takze na zasobniku zadnej bordel nezustane i kdybys preskocil do funkce ktera ocekava uplne jinej stack frame...
Dělal. Z80, x86, 8051, AVR, DSP od TI, MSP430, H8/300H, SH2A, SH4, PowerPC, ARM7TDMI, ARM9EJ-C, Cortex M0, Cortex M3. Když píšeš bootloader nebo system itni, a je to ve tvojí režii, moc se k výsledkům překladače nedostaneš. A registr BP jsem mimo x86 neviděl nikde :P Navíc výsledke překladače hodně závisí na platformě a na překladači, jiný věci fluše GCC, jiný IAR EW, jiný Keil... Liší se i správa paměti.
Když return přeskočíš, neobnoví se vůbec nic. To je jednoduchý. A soustředěnýmu náporu blbosti neodolá nic. Stačí, když někdo místo "return" napíše "__asm{ret}", protože si všiml, že to ušetří pár bytů ve FLASH a je vymalováno...
Navíc v komerčním prostředí u embedded systémů je často požadavek na multiplatformní podporu. Co funguje na jednom broukovi v jednom kompilátoru, to na druhým dělá nečekaný žertíky...