Meghasonlás
A reggeli fekete mellett ma a jól tesztelhető kód követelményein töprengtem. Nem tűnt túl laza kapcsolásnak a vezérlőben rögzíteni a modellosztály fájlnevét. Ami azt illeti, egy modellosztály nevét magát sem tűnik jó ötletnek rögzíteni, hisz bármikor felmerülhet az igény másik használatára, rögtön teszteléskor.
De ha már itt tartunk: ezen gondolatmenet mentén egyáltalán nem tűnik okosnak osztályokat nevesíteni, még a szülőét sem. Miért is ne adódhatna úgy, hogy ugyanazon osztállyal idővel egy másikat szeretnék kiterjeszteni? Így aztán persze az osztályoknak nevet adni is okafogyottá válik.
Várj.
Úgy-e, a globális változók rosszak? A hagyományos nyelvi közegben mozgónak furcsán hathat, de például Ruby-ban a szóelemzés elve azt mondja, hogy az osztály is csak objektum, a neve pedig mindprózaian egy konstans. Egy globális konstans.
Immár ebből a perspektívából is vizsgálatnak alávetve a kérdést, nem volna hát racionális az eljárásaink minden függőségét kívülről injektálni? Persze akkor még mindig ott van választott dialektusunk kész szókincse, de most képzeljünk el egy nyelvet, amiben hatókör nem öröklődik, globális elérés pedig nem létezik. Minden darab kód függőségeinek kielégítése a hívó feladata, történjék ez bár minden futáskor argumentumként, avagy előre paraméterezve curry-zés vagy ekvivalens technika használatával. Egy ilyen nyelv a biztonságra érzékeny fejlesztők Szent Grálja, Fekete köve és frígyládája lenne.
Viszont gondolkozzunk tovább! Egy olyan függvény, melynek át kell adnom azon (mondjuk beépített) osztályt, melynek példányát csak hasznosítja, de nem az művelete tárgya, vajon nem sérti-e csúnyán az információrejtés elvét, nem rútítja-e ocsmány implementációs részletekkel a felületet?
De fordítsuk meg a dolgot: ha a hívó fél eredményorientált, s a megvalósítás kérdései hidegen hagyják, úgy nem legitim-e a globális változóban tárolt adatbáziskapcsolat, mondván, hogy a modell dolga valahogy perzisztálni az adatot?
Ezen a ponton úgy érzem, lövészárokháborúba sáncoltam magam, az olvasók személyében kívánnék új harcoló feleket bevonni a konfliktus rendezése érdekében.
■
interfész-használat, IoC
Factory Pattern, DI
Factory: bár meg kell nevezni a factoryt magát, de mégis elég azt mondanunk, hogy kérünk egy ilyet, és kapunk valamit, aminek a felülete olyan.
Dependency Injection: Ez ugye lényegében az, amit írtál. Véleményem szerint ha minden függvénynek injectálni kell az összes függőségét, az nagymértékben rondítja az interfacet.
Ha figyelembe vesszük a performance/áttekinthetőség/karbantarthatóság szempontokat, akkor ugye egy egyensúlyt kell találnunk a dinamikusság/laza közés és a tiszta interface/hardcoded függőségek között.
Szerintem általában megoldható, hogy egy rendszert kisebb modulokra szedünk szét, és ezeknek a moduloknak injectálunk külső serviceket (db, config). A kérdés az ilyen modulok mérete lehet. (Való életben ilyen modul: Django app, Symfony2 Bundle)
nem rútítja-e ocsmány
DE. :D :D :D
Köszi
mindig szembe fog allni
egyik oldalrol a tokeletesen tesztelheto kod stateless, a bemeneti parameterei alapjan determinisztikus.
onnantol kezdve, hogy van akarmilyen lokalis, vagy globalis valtozod, ami allapotot tarol, mar nem igaz ez az allitas, ha tobbszor meghivod ugyanazt a fuggvenyt/metodust, ugyanarra a bemenetre tobbfele kimenetet is kaphatsz.
de ha igy tekintunk az egeszre, akkor rajovunk, hogy onnantol kezdve, hogy fajlhoz, adatbazishoz, vagy egyebb kulso eroforrashoz nyulunk (system hivas direkt(kodfuttatas) vagy indirekt modon(pl. rendszerido lekerdezese, random generalas), file muvelet, adatbazismuvelet, etc) akkor mar bevezetunk valamifele kulso dependenciat a kodba.
ezert kijelentheto, hogy nehany specialis esettol eltekintve mindig lesz valamifajta nemdetermisztikus befolyasoltsaga a kodunknak.
http://en.wikipedia.org/wiki/Functional_programming
In practice, the difference between a mathematical function and the notion of a "function" used in imperative programming is that imperative functions can have side effects, changing the value of program state. Because of this they lack referential transparency, i.e. the same language expression can result in different values at different times depending on the state of the executing program. Conversely, in functional code, the output value of a function depends only on the arguments that are input to the function, so calling a function f twice with the same value for an argument x will produce the same result f(x) both times. Eliminating side effects can make it much easier to understand and predict the behavior of a program, which is one of the key motivations for the development of functional programming.[1]
nehany szituacioban a funkcionalis nyelvek nagyon hasznosak lehetnek, de az atlagos programozo a valos elet problemaiban tobbnyire kulonbozo allapottarto rendszerekkel kommunikal, adatokat fogad, es tovabbi, esetleg modositja is menet kozben.
A feladat megtalalni a megfelelo egyensulyt az onjaro komponensek, es a hasznalhatatlanul nehezkes, de nagyon decoupled rendszer kozott.
Tyrael
Mi a cél?
Nem fogok dependency injectiont használni mindenhol mert az a divatos. Majd ott, ahol szükséges. Halál nyugodtan be fogom vezetni azt a 3-4-5 db. globális változót, amiről tudom, hogy az márpedig fix, és azt fogja használni minden, ha tetszik ha nem, mert az esetek 99%-ában ez fog kelleni. (Maradék 1% miatt meg nem fogom szívatni magam).
Azt látom mostanság, hogy egy primitív blogmotort nem tudnak ma már megírni az emberek MVC pattern, valamilyen keretrendszer és hozzá külön egy entity framework nélkül. Nem látom értelmét az architektúrális felhőkarcolók építgetésének csak azért, hogy legyenek meg mert ez a divat mostanság. Vagy hozhatnám példának az MVVM patternt. Nagyon szép és jó, hogy agyonrétegezett, de 6*10^23 rétegen kell átvezetnem mindent, és horribilis mennyiségű kódot kell írnom csak azért, hogy szép legyen.
Igazából aki a mindenféle modern és divatos eszköz használatát fontolgatja, annak csak azt tudom javasolni, hogy először is gondolja át, hogy valóban kell-e ez neki és valóban ad-e annyi pluszt, mint amennyit elvesz (idő, mire megtanulja, idő, mire a meglévő kódokat átportolja/újraírja az új módszerhez, időtöbblet a régi és az új módszerhez képest).
Szépen kialakult a thread
Szörnyű, és a döntések többségében megérzésből választok, ami azt eredményezi, hogy ugyanaz a kódsor (kicsit módosítva persze) egyszer a controlban, egyszer meg a view-ban van. Valahogy sosem sikerül eltalálnom, hogy hova _szoktam_, és logikusan végiggondolva pedig mindkét helyre beillene.
Ezért többször van az, hogy átnézek fölöslegesen két réteget csak azért, hogy tudjam, mit hova tettem, illetve, éppen hova kellene tennem azt, ami a fejemben van.
(Azt most meg sem említem, hogy nem csak az adatbázis tábláknak, de a hasonló nevű view-knak is vannak nálam MVC megfelelői, és pl. a renderelést azokhoz teszem, mert abban vannak a megfelelő adatok. A módosítást meg a base táblába, mert dbview-n keresztül ne módosítsunk már adatot. Így meg aztán szorzódnak a lehetséges helyek :)
MVC keretrendszert használok,
Tudnál példát mondani? Én nehezen tudom elképzelni, hogy azon dilemmázok, hogy mi hova menjen, de kíváncsi vagyok, hátha tényleg van ilyen helyzet. :-)
Például. Amikor egy
Amikor egy táblázatot iratok ki úgy, hogy mondjuk adott tartalmú sorait kiszűröm (whateva, hogy miért php oldalon szűrök, csak a példa kedvéért).
Mert ugye a mondás az, hogy a renderelés a view-ban történjen, tehát szépen átadom a modelből visszakapott adatokat a template rendszernek, és az meg kiírja. Viszont a sorokon végig kell mennem, hogy tudjam, hogy irassam-e ki vagy sem.
A kérdés:
- controlban iterálok, és külön metódusokat hívok meg a view-ban a táblázat keretének és sorainak kiiratására
- az egész iterációt feltételvizsgálattal beleteszem a view-ba
- controlból hívok meg egy view metódust, ami visszaad egy html kódot, majd azt továbbadom egy másik view metódusnak
Egyéb szcenárió? :)
Más
Mi az egész? :) Na, legyen
Na, legyen világos a példa: 5 usert kell kilistáznom táblázatban úgy, hogy a 3-as id-jűt nem írom ki. Tekintsünk el attól, hogy ez sql-ben könnyen megoldható, a kérdés nem erre vonatkozik.
Tehát mi hol foglal helyet ebben az esetben?
inf3rno egyébként azt mondja, hogy a szűrést a view-ban oldjam meg.
A "nagyjából mindegy" pedig szüli az inkonzisztenciákat, tehát valamihez kötni kell, különben hol itt lesz, hol ott.
Feldolgozás
Controller:
Feldolgoznám a kérést, ami ugye megmondja, hogy mit kell listázni, és ebből mit nem kell megjeleníteni.
Model:
Elvégzi a lekérdezést, majd kiszűri az adatokat, vagy amennyiben lehetséges, akkor már maga kiszűri a nem szükséges adatokat.
View:
Megjeleníti a táblázatot, amiben minden átadott adat benne van. Már nem kell a szűréssel foglalkozni, mivel az adat már fel van dolgozva. Amennyiben meg kell jeleníteni 3-as IDjű elemet, de mondjuk más színnel ki kell emelni, akkor pedig a szűrést már a View rétegbe tenném.
A Controller semmi mast nem
Amibol szerintem a legtobb kavarodas van, az az, hogy sok ember nincs tisztaban vele, hogy nem csak egyfele model van, legalabbis az MVC-ben helyett foglalo M betu nem csak egyfele modelt takar, viszont sokan hajlamosak abba a hitbe esni, hogy ez a Model csak a DAO modelleket jelenti, pedig ugye a modelleknek ez csak egy nagyon kis resze, gyakorlatilag a teljes alkalmazaslogikanak itt van a helye (Tehat van egy Modellunk, ami a felhasznalokat listazasahoz kikeresi a felhasznalokat, ennek a Controller atadhatja, esetleg transzformalhatja a bemeneti parametereit, majd ezt a model-t, vagy ennek az eredmenyet atadja a View-nak, ahol a latogato szamara reprezentativ formaban megjelenitesre kerul).
http://en.wikipedia.org/wiki/Model-view-controller
http://en.wikipedia.org/wiki/Multitier_architecture
http://en.wikipedia.org/wiki/Business_layer
Tyrael
+1
Kavarodás nem csak a modelnél van, hanem a viewnál is, sokan keverik a view réteget a sablon rendszerrel ugyanúgy, mint a modelt a dao-val.
Kérdés
Ha kicsit jobban megnézed a
Model alatt nem 1-1
masodik kerdesedet itt nagyon szepen megvitattak
Tyrael
A kérdés: - controlban
- controlban iterálok, és külön metódusokat hívok meg a view-ban a táblázat keretének és sorainak kiiratására
- az egész iterációt feltételvizsgálattal beleteszem a view-ba
- controlból hívok meg egy view metódust, ami visszaad egy html kódot, majd azt továbbadom egy másik view metódusnak
Egyéb szcenárió? :)
A controller-nek inkább olyan feladata van szerintem, hogy az auth-ot lekezelje, ellenőrizze a jogosultságokat, a post adatokat validálja, és eljuttassa őket a megfelelő model/view példányokhoz. Ha már megtörtént aminek kellett, mondjuk egy tábla módosítása, stb, akkor a kirajzolásnál a view fog irányítani. Szóval a te esetedben a view fogja elkérni az adatokat a model-től a táblázathoz. Az adatok szűrését megoldhatod a model-ben és a view-ban is, nagyjából mindegy, nyilván ha az sql-be be tudod tenni, akkor a model-be fog kerülni a dolog.
(A template nem egyenlő a view-al. A view használhat templateket arra, hogy szöveges formára hozza az adatokat, ha éppen arra van szükség, de mondjuk egy képet sosem fogsz kirajzolni templattel.)
http://www.youtube.com/result
Tyrael
MVC esetében például egészen
Saxus: "horribilis mennyiségű kódot kell írnom csak azért, hogy szép legyen." pedig pont az ellenkezője a lényeg, a szerepkörök jó elkülönítése, a kód újrafelhasználhatósága.
Persze nem vitatom, hogy sok technika "hasznossága" függ a projekt méretétől is, de egy e-mail form vagy egy szavazás box esetében nincs is értelme ezeknek a fogalmaknak, értelemszerűen nagy méretű projektekre vonatkoznak.
"értelemszerűen nagy méretű projektekre"
Az általam fentebb említett MVVM patternnek is látom az értelmét, csak épp nem ott, ahol a projektek 90%-a készül, főleg itthon. Ellenben viszont a trend az, hogy ész nélkül használjuk mindenre az MVC, ORM mapping és hasonló három betűs megoldásokat, holott ugyanolyan szépen meg lehetne oldani, csak épp nem "trendi" ezért "nem szép".
Pl. egyszer úgy nézett ki, hogy átadunk egy projekt részfeladatát egy külsős programozónak. Mikor szóba került, hogy mi a véleménye a projektről, csak annyit tudott hozzátenni, hogy "nagy szar" a miértre meg azt, hogy "mert globális változók vannak benne". Na most a projektben legalább 3 részt tudnék mondani, ami az idők folyamán nagyon csúnyán elgányolódott az örökös variálás és toldozás-foltozás mellett, és az a 4 globális változó zavarja a legkevesebb vizet...
Alapvetően egyetértek veled
Annyiban tér el a véleményünk, hogy itt nem a szépségről van szó, annál sokkal fontosabb dolgokról... Ha az 5 osztályt használó személyes blogodban ki kell cserélned a template engine-t vagy az adatbázismotort, akkor esetleg egy search-and-replace-szel meg egy fél órás hegesztéssel meg is vagy.
Ha ezt egy megfelelő absztrakciót nélkülöző több százezer kódsorból felépülő rendszerben kell megtenned, ott már szaban vagy :) nem a szépség a lényeg, hanem a maintainability, reusability, ease of testing, és hasonló magyarul hülyén hangzó kifejezések :)
Magyarul hülyén hangzó
Rendben, helyesbítek,
de ez egy végtelen hosszú beszélgetés tárgya lehetne, valószínűleg mindenkinek az hangzik "nemhülyén", ahogy eredetileg ismer egy szakkifejezést... valószínűleg az "egyke osztály" sem mindenkinek borzolja fel a hátán a szőrt. :)
Alapveto epitokovek csereje
Masik: sajnos a tapasztalatom az, hogy szep szo a kodujrafelhasznalhatosag (megis mi a baj vele?), de a keretrendszer relative fix, a modulokban meg ugy is van olyan kulonbseg, hogy idovel elganyolodjanak, ha valoban hozza kell nyulni. Ilyenkor neha tisztabb-szarazabb uj dolgot tervezni a regi kodreszleteket felhasznalva.