ugrás a tartalomhoz

Megnéznétek, hány hibát követtem el?

eddig bírtam szó nélkül · 2012. Jún. 6. (Sze), 22.47
Megint nekiestem a PHP+OOP "tanulásnak".
A mostanában tanultak alapján összeraktam egy kezdetleges kódot, aminek a feladata az lenne, hogy "valahonnan" kiolvassa az alkalmazás működéséhez szükséges paramétereket és ezeket elhelyezze egy tömbben.
A "valahonnan" elméletileg lehetne akár hagyományos ini fájl (csak ez készült el), de elképzeléseim szerint mind a formátum (pl. ini helyett XML), mind az adatforrás (pl. fájl helyett adatbázis) szabadon változtatható.
Ehhez szerettem volna felhasználni a dependency injectiont is, nem tudom, ez mennyire sikerült.

Ha van kedvetek, türelmetek átnézni kb. 80 sort: http://pastebin.com/adruq7y9
Minden kritikát szívesen fogadok.
(azt is, ha egyértelmű, hogy totál hülye vagyok hozzá, mert akkor nem erőltetem tovább ;-) )

ui: kommentek azért nincsenek, mert az olvastam a Tiszta kódban, hogy ha egyébként olvasható a kód, eléggé beszédesek a használt nevek, akkor a megjegyzés csak nehezíti az olvasást. Hát szót fogadtam neki... :-)
 
1

Nem

janoszen · 2012. Jún. 7. (Cs), 00.14
A jó komment nem azt írja le, hogy MIT csinálsz, hanem hogy MIÉRT csinálod. A kódodat holnap megnézem.
2

Van benne valami...

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 00.23
Vedd úgy, hogy ez szimplán kötekedés a könyv szerzőjével. ;-)

Nem tudnám szó szerint idézni, de kifejezetten olyan megfogalmazásra emlékszem, hogy a jó kód olvasható kommentek nélkül is és csak ha nagyon muszáj, akkor írjuk le, hogy mit, miért. Mert normálisan olyan kell legyen, mint egy regény, amit valamely informatikában használatos nyelven írtak.
(ha nem felejtem el, megkeresem és bemásolom ide - nekem kicsit égnek állt a hajam, amikor olvastam)
11

Megjegyzést ott kell írnod,

Joó Ádám · 2012. Jún. 7. (Cs), 16.10
Megjegyzést ott kell írnod, ahol nem egyértelmű, hogy mi történik. A jó kódot olvasva mindig egyértelmű, hogy mi történik, mert áttekinthetően formázott, és beszédes azonosítókat (változókat és típusneveket, az utóbbin a hangsúly) használ.
3

Nagyjából jó, pár dolog:-

inf · 2012. Jún. 7. (Cs), 03.30
Nagyjából jó, pár dolog:
- Használj interface-eket absztrakt osztályok helyett!
Egy csomó felesleges absztrakt osztályt létrehozol csak validálási céllal...

- Az elnevezések jók, ami fura az a ParametersFromFile.
Az ilyesmiket inkább Loader-nek vagy Reader-nek hívják, mert az sokkal jobban elmondja, hogy mit csinálnak. A ParametersFromFile egy magas absztrakciós szintű elnevezés, viszont az osztályban egy alacsony absztrakciós szintű kód van, aminek egyáltalán nem kell tudnia arról, hogy ő most paramétereket olvas fájlból, vagy dalszöveget, csak annyit, hogy valami adatot ... Amelyik osztályod tudja, hogy paramétereket olvasol be, csak ott nevezheted el ezt paraméter beolvasónak...

class ParameterUser {

    public function needParams() {
        $parameterReader = new DataReader();
        $parameters = $parameterReader->read();
        //...
    }

}
- A hármas constructor injection nagyon csúnya:

$setupParameters=new ApplicationSetup(new IniParser(new ParametersFromFile("../config/setup.ini")));
Inkább tedd változókba a példányokat helyette... (Clean Code / Objects and Data Structures / Train Wreck) Nem az a cél, hogy minél több metódust (jelen esetben konstruktor hívást) egymás után fűzzél, hanem az, hogy pontosan tudjuk, hogy mi csinál mit (milyen objektumon milyen metódust hívsz meg)...

- Használj dependency injection container-t paraméterezéshez!
Így nem kell az ApplicationSetup példányosításnál azzal törődnöd, hogy a .ini fájlhoz IniParser kell, stb... Ami a config olvasónál automatizálható, azt meg tudod oldani DIC-vel, és csak azokat a paramétereket kell megadnod a végén az ApplicationSetup-nak, amire tényleg feltétlen szüksége van.

Dependency injection-nel ez valahogy így nézne ki:


$setup = new ApplicationSetup();
$setup->configure(new ConfigFileReaderContainer('../config/setup.ini'));

class ApplicationSetup {

    protected $params;

    public function configure(ConfigReaderContainerInterface $configReaderContainer) {
        $configReader = $configReaderContainer->getConfigReader();
        $this->params = $configReader->read();
    }

}

interface ConfigReaderContainerInterface {

    /** @return ReaderInterface */
    public function getConfigReader();
}

class ConfigFileReaderContainer implements ConfigReaderContainerInterface {
    /** @var ConfigResourceReader*/
    protected $reader;

    public function __construct($configFile) {
        $this->reader = new ConfigResourceReader();
        $this->reader->setResourceReader(new FileReader($configFile));
        $extension = pathinfo($configFile, PATHINFO_EXTENSION);
        if ($extension == 'ini')
            $this->reader->setConfigParser(new IniParser());
        else
            throw new Exception('Mime type not supported.');
    }

    /** @return ReaderInterface */
    public function getConfigReader() {
        return $this->reader;
    }

}

interface ReaderInterface {

    public function read();
}

interface ParserInterface {

    public function parse($data);
}

class ConfigResourceReader implements ReaderInterface {

    /** @var ReaderInterface */
    protected $resourceReader;

    /** @var ParserInterface */
    protected $configParser;

    public function setResourceReader(ReaderInterface $resourceReader) {
        $this->resourceReader = $resourceReader;
    }

    public function setConfigParser(ParserInterface $configParser) {
        $this->configParser = $configParser;
    }

    public function read() {
        $config = $this->resourceReader->read();
        return $this->configParser->parse($config);
    }

}

class FileReader implements ReaderInterface {

    protected $file;

    public function __construct($file) {
        $this->file = $file;
    }

    public function read() {
        $data = file_get_contents($this->file);
        if ($data === false)
            throw new Exception('Cannot read file.');
        return $data;
    }

}

class IniParser implements ParserInterface {

    public function parse($data) {
        $data = parse_ini_string($data);
        if ($data === false)
            throw new Exception('Cannot parse data.');
        return $data;
    }

}
Amire közben rájöttem, hogy ha csak simán ReaderInterface-t várnál el az ApplicationSetup-ban, akkor a FileReader-t is meg lehetne adni. Na a FileReader nyilván nem lenne valid, szóval létre kellene hoznom egy külön interface-t, amivel tudom validálni, hogy mit fogad el az ApplicationSetup, vagy utólagosan ellenőriznem kéne a kiolvasott adatot, hogy megfelel e a követelményeknek. Ebből már elég nyilvánvaló, hogy a dependency injection container nem csak arra jó, hogy bekonfigurálja jelen esetben a ReaderInterface-t teljesítő osztályokat, hanem arra is, hogy biztosítsa, hogy ezek közül a megfelelőeket lehessen csak injektálni. Szóval ha egy adott interface-t várunk el, és az túl általános, akkor DIC-vel tovább lehet szűkíteni az elfogadott osztályok számát...

szerk:
Hmm a ConfigReader elnevezés helyett valami olyasmi lenne beszélőbb, hogy SerializedDataReader, de nem igazán találtam meg a megfelelően tömör kifejezést...
4

Köszi!

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 07.10
Ezen most lesz mit rágódnom. :-)
<defense mode>
Neveket sohasem fogom úgy kialakítani, hogy elfogadható legyen.
Hibakezelés meg azért nem volt, mert ezt csak egy "csontváznak" szántam, hogy az elvekből megértettem-e valamit
</defense mode>

Interface-ek kapcsán... Úgy emlékszem, a PHP megengedi, hogy absztrakt osztályokban nem absztrakt metódusokat is létrehozzak. (mintha pl. a Java ezt tiltaná)
Azért nem használtam interface-t, mert ne legyen szükség duplázni bizonyos dolgokat.
De ha jól értem, akkor az ilyesmit inkább úgy, hogy a közös, azonosan működő metódusokat egy ősosztályba tenni és attól örökölni, amit meg absztrakt metódusként írnék, azt interface-ből átvenni?
14

Jó az absztrakt osztály, ha

inf · 2012. Jún. 7. (Cs), 17.13
Jó az absztrakt osztály, ha tényleg sok lenne a duplázás, de akkor is egy interface-t implementáljon inkább az absztrakt osztály, és az interface-t követeld meg. Sokkal rugalmasabb úgy a kód.
32

abstract vs interface

eddig bírtam szó nélkül · 2012. Jún. 9. (Szo), 11.37
Update: most olvasom el tizedszer az alábbi hozzászólásomat, de még mindig nem értem, hogy került ide.
Gyanítom, mellényúltam, mert ez így olyan, mintha magamnak válaszoltam volna. :-)

------------------------------------------------------------
PHP-ben működik, de - utána kellene néznem, hogy még mindig igaz-e - pl. javaban az abstract osztály kizárólag abstract metódusokat tartalmazhat, ott leszámítva, hogy kizárom a többszörös öröklést (aminek előnyét nem igazán látom), fogalmam sincs, mi különbség van az abstract class és az interface között.


Nagyon egyszerű. Egy osztálynak csak egy őse lehet, viszont annyi interfacet implementálhat, amennyit nem szégyellsz...
6

Amit nem értek a tiédből....

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 09.19
Nekem eleve olyan elképzelésem volt, hogy az alkalmazásra bíznám, hogy milyen forrásból és milyen jellegű adatokból akar dolgozni.
Nálad csak az .ini fájl nevét adhatom meg. Ez nem jelent problémát/valamilyen OO elv megsértését?
Vagy pont azzal sértem meg, ha kívülről akarom befolyásolni pl. azt, hogy a paraméter olvasóm milyen parsert használjon?
(itt kezdek elvenni a felelősségi körök, egységbe zártság és hasonló témákban)
13

Nálad csak az .ini fájl nevét

inf · 2012. Jún. 7. (Cs), 17.11
Nálad csak az .ini fájl nevét adhatom meg. Ez nem jelent problémát/valamilyen OO elv megsértését?

Jobb példát írni, mint magyarázni...
Tegyük fel, hogy megadod az XML kódot, amiből be akarod parsolni a config-ot (szóval nem fájlból akarsz parsolni...

$setup = new ApplicationSetup();
$setup->configure(new ConfigTextReaderContainer('<config>...</config>', new XmlParser()));

class ConfigTextReaderContainer implements ConfigReaderContainerInterface {

    /** @var ConfigResourceReader */
    protected $reader;

    public function __construct($configText, ParserInterface $parser) {
        $this->reader = new ConfigTextReader();
        $this->reader->setText($configText);
        $this->reader->setParser($parser);
    }

    /** @return ReaderInterface */
    public function getConfigReader() {
        return $this->reader;
    }

}

class ConfigTextReader implements ReaderInterface {

    protected $text;

    /** @var ParserInterface */
    protected $parser;

    public function setText($text) {
        $this->text = $text;
    }

    public function setParser(ParserInterface $parser) {
        $this->parser = $parser;
    }

    public function read() {
        return $this->parser->parse($this->text);
    }

}

class XmlParser implements ParserInterface
{
    //...
}
Ha olyat akarsz, hogy kívülről lehessen befolyásolni, hogy milyen Parser-t használjon, akkor csinálsz egy olyan Container-t, ami ezt lehetővé teszi. Azt hiszem elég egyértelmű...
7

Reader vs. Parser?

T.G · 2012. Jún. 7. (Cs), 09.22
Szerintem ez túl lett bonyolítva.

A ConfigReaderContainerInterface-nek más felhasználása van, mintsem a ConfigFileReaderContainer –t kiegészítse? Elsőre nem látszódik, hogy hol segít? Miben lenne más, ha az ApplicationSetup::configure egy ConfigFileReaderContainer –t várna paraméterben?

A ConfigResourceReader, aki maga is egy ReaderInterface van egy property-je, ami szintén ReaderInterface? Vagy valamit félrenézek? Ez nekem nem annyira érthető, miért kellett így csinálni?

Illetve a ParserInterface az egyben ReaderInterface? Ez sem egyértelmű elsőre, hogy miért kell? Főleg, hogy a IniParser-nek jelenleg nincs read metódusa, ami fordítási hiba.
12

Kösz, javítottam, a Parser az

inf · 2012. Jún. 7. (Cs), 16.51
Kösz, javítottam, a Parser az nem Reader egyben.

A ConfigReaderContainerInterface-nek más felhasználása van, mintsem a ConfigFileReaderContainer –t kiegészítse? Elsőre nem látszódik, hogy hol segít? Miben lenne más, ha az ApplicationSetup::configure egy ConfigFileReaderContainer –t várna paraméterben?

A ContainerInterface azért kell, hogy ha máshonnan akarsz beolvasni (ConfigMemoryReaderContainer, ConfigCosmicEnergyReaderContainer etc.) adatot, akkor arra is tudj egy külön container-t csinálni. Mindenképp kell egy másik interface a ReaderInterface-en kívül, ami biztosítja, hogy a setup valid Reader-t kap, mivel a ReaderInterface túl általános. Pl egy FileReader az nem lenne valid, mert szöveget ad át a paraméterek tömbje helyett...

A ConfigResourceReader, aki maga is egy ReaderInterface van egy property-je, ami szintén ReaderInterface? Vagy valamit félrenézek? Ez nekem nem annyira érthető, miért kellett így csinálni?

Nem muszáj így csinálni, nekem egyszerűen így volt logikus. Mindkettő adatot olvas be, annyi a különbség, hogy a Config-nál még utánatettem egy parser-t, de attól még ugyanúgy adat beolvasás annak is a célja.
15

DI

janoszen · 2012. Jún. 7. (Cs), 17.16
A Dependency Injection Containerrel nem értek egyet. Megöli a kódkiegészítést és viszonylag keveset hoz.

Amivel nekem a kódban bajom van, az az, hogy a legritkább esetben van arra szükség, hogy több féle formátumból tudjon egy alkalmazás konfigurációt olvasni. Sőt, kontraproduktív, mert mindegyikhez kell megfelelő dokumentációt írni. Innentől kezdve én azt mondanám, hogy az alkalmazás írja elő, mit szeretne.

Ami az interfaceket illeti, az előttem szólónak igaza van. Ha le akarsz írni egy szabványt, használj interfacet. Ha tényleg logikailag közös őse van két osztálynak, akkor legyen absztrakt ősosztály.
16

Amivel nekem a kódban bajom

inf · 2012. Jún. 7. (Cs), 17.21
Amivel nekem a kódban bajom van, az az, hogy a legritkább esetben van arra szükség, hogy több féle formátumból tudjon egy alkalmazás konfigurációt olvasni. Sőt, kontraproduktív, mert mindegyikhez kell megfelelő dokumentációt írni. Innentől kezdve én azt mondanám, hogy az alkalmazás írja elő, mit szeretne.


Ezzel egyet értek. Úgy értelmeztem a feladatot, hogy általános kódra van szükség. Ha én csinálnám magamnak, akkor egy sima fájl olvasó meg parser lenne, mert mindig fájlból szedem a config-ot. Egyébként nagyon könnyű abba a hibába esni, hogy túl általános kódot ír az ember, én inkább úgy szoktam, hogy megnézem, hogy az adott pillanatban mire van szükség, azt megcsinálom, aztán ha valamikor előfordul, hogy mondjuk nem csak fájlból akarok olvasni, akkor az előző változatot módosítom úgy, hogy az új elvárásoknak is megfeleljen. A túl általános kód egy csomó plusz munkával jár, ami az esetek nagy részében nem térül meg.
17

DIC és egyebek...

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 17.25
E téren (dependency injection) még mindig ott tartok, hogy próbálom értelmezni és nem állítom, hogy sikerült. :-)
Viszont a dologhoz hozzátartozik, hogy ez az egész ama bizonyos állatorvosi lónak a tipikus esete: megpróbálom valóra váltani mindazt amit a már többször említett, Tiszta kód c. könyvben olvastam. Kommentek, elnevezések és ebben az esetben a kód újrahasznosíthatóság.
Egyetlen alkalmazásban tényleg ritkaság, hogy hol .ini-ből, hol .xml-ből, hogy egyéb akármiből kell felparaméterezni magát az applikációt, de... Ezt egyszer megírom és csak a parsert kell cserélni, ha máshol mást kell alátolni.

Ez volt az eredeti elképzelésem.
Hogy mi lett belőle... az más kérdés.
18

Tiszta kód

T.G · 2012. Jún. 7. (Cs), 18.13
Nekem azért van egy olyan érzésem, hogy néhol nagyon félreértetted a Tiszta kód könyvet. :)

Merthogy, nagyon könnyű rossz kommentet írni, és erre vannak a könyvben példák, de nem azt írta, hogy egyáltalán ne írjunk kommentet.
Illetve ott is van egy ellentmondás, hogy a sok kicsi osztály akkor kell, amikor valóban sok kis feladat van. De ha csak egy kis feladat van, akkor nem kell felesleges osztályokat gyártani.
20

félreértés

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 18.23
Igen, könnyen lehet, de azért van benne némi szándékosság is. :-)
Pontosabban "ész nélkül" követve azt, amit ott leírtak, kb. ez lesz a végeredmény.

(bevallom, nem tetszik a szerző stílusa... Van benne valami... nem tudom megfogalmazni, de valami nagyon zavaró.)
19

Re: DI

T.G · 2012. Jún. 7. (Cs), 18.15
A Dependency Injection Containerrel nem értek egyet. Megöli a kódkiegészítést és viszonylag keveset hoz.


Ez a megjegyzésed csak erre a konkrét példára vonatkozik, vagy általánosságban a DIC-et nem támogatod?
21

Na erre én is kíváncsi

inf · 2012. Jún. 7. (Cs), 19.41
Na erre én is kíváncsi vagyok, meg arra is, hogy hol öli meg a kódkiegészítést :-)
23

Nézzük

janoszen · 2012. Jún. 7. (Cs), 20.49
Nézzük például a Fabian Potencier-féle megvalósítást amiben van egy ArrayAccess objektumod, amibe tudsz minden félét belepakolni, de igazából bár milyen DI containerre igaz lesz. Egy string kulcson eltárolsz benne _valamit_. A kódban egy másik helyen használod ezt a valamit. Nincs garanciád (nem hogy kód hinted) arra, hogy az a valami tényleg megvalósítja azt az interfacet, amit Te elvársz. A fenti példában:

$db = $dicontainer['database'];
$db->/* és itt hiába nyomogadot a Ctrl + Space-t */
Ha ezt megpróbálod megkerülni, muszáj vagy a DI containerek kívül implementálni lekérő függvényeket, amik dokumentációjában benne van az, hogy mit adnak vissza:

/**
 * @return Database
 */
function getDatabase() {
    return $this->dicontainer['database'];
}
A DI containerre nem rakhatod ezt a függvényt, hiszen akkor pont az értelmét veszítené el, mivel minden egyes service típust kézzel rá kell ragasztani, ráadásul túl is lépi a hatáskörét.

De természetesen FIXME, ha tévednék.
24

Hát lehet, hogy az én

inf · 2012. Jún. 7. (Cs), 21.18
Amit leírsz az egy sima gyűjtemény, amivel adatot továbbítasz, és nem egy DIC.
Itt egy kicsit máshogy írja a Potencier. Ezek alapján nekem az jött le, hogy a DIC-nek az a feladata, hogy a konfigja alapján objektumokat szolgáltasson, nem pedig az, hogy gyűjteményként viselkedjen, szóval hogy az egyik oldalán megadsz objektumokat, a másik oldalán meg kiveszed belőle ugyanazokat. A DIC maga példányosít, így tudja garantálni, hogy amit mondjuk a getDatabase visszaad az PDO osztályú, stb... Persze lehet, hogy én vagyok a hülye :D
25

OK

janoszen · 2012. Jún. 8. (P), 00.05
Még ha így is van, akkor is igaz a fenti. Ha string alapján kérsz le valamit, akkor nem lesz type hintinged, ha pedig függvényeket csinálsz rá akkor megette a fene az egészet.
26

A string alapján lekérés

inf · 2012. Jún. 8. (P), 02.02
A string alapján lekérés szerintem is marhaság. A függvény csinálást még ki fogom próbálni több példán, hogy tudjak nyilatkozni róla. Amúgy terveztem, hogy írok clean code cikket (esetleg sorozatot), pár vázlat van is, csak idő hiányában félbe maradt. Most nyáron biztosan nem lesz meg, mert annyi a projekt, de ősszel remélem tudok foglalkozni vele. Gondolom az majd jól felkavarja a port, ha már egy dependency injection-ön sem tudunk megegyezni :-)
27

Radikális

janoszen · 2012. Jún. 8. (P), 04.19
Én meglehetősen radikális vagyok ebből a szempontból. Nem szeretem, ha kódolás közben valami akadályoz a folyamatos munkában. Na, a kódkiegészítés hiánya vagy a boilerplate kód tipikusan ilyen. Inkább beáldozom a tesztelhetőséget, mert az esetek többségében úgysem készül teszt és akkor tisztább lesz a végeredmény.
30

Nem hiszem, hogy annyira

inf · 2012. Jún. 8. (P), 18.23
Nem hiszem, hogy annyira radikális lennél, én is igyekszem mindent úgy írni, hogy menjen hozzá a kódkiegészítés...
22

Konkrétan

janoszen · 2012. Jún. 7. (Cs), 20.43
Nekem konkrétan azzal van bajom, hogy ha a dependency injectiont stringgel paraméterezed, akkor nem lesz kódkiegészítésed, ha pedig megpróbálod megoldani, lesz egy rakás boilerplate kódod, amit karban kell tartani.

Én inkább a sima dependency injection híve vagyok. Igaz nem olyan univerzális megoldás, de egyből látod, milyen osztály van ott, működik a kódkiegészítés is és nem is kell varázsolni.
5

Az elnevezések kicsit

tgr · 2012. Jún. 7. (Cs), 09.09
Az elnevezések kicsit zavarosak, pl. van egy setupParameters változó, erről azt gondolná az ember, hogy a Parameters osztály egy példánya, de nem, mert az az osztály a paraméterek betöltését végzi... az ApplicationSetup meg úgy hangzik, mintha csinálna valamit, inkább Parameters, Configuration, Settings vagy hasonló nevet adnék neki. Illetve következetes változónév-konvenciókkal le lehet rövidíteni a függvényneveket, pl. $setupParameters->getAllParameters() helyett $setupParameters->getAll() is tökéletesen olvasható (ha a paramétertároló osztályod a paramétereken kívül mást is tárol, akkor amúgy is gyanús, hogy sérült a single responsibility principle).

Az ApplicationSetup konstruktora nemtriviális munkát végez, ami dependency injectionnél problémákat okozhat. Egyáltalán, miért a paramétereket tároló/visszaadó osztály felelőssége a beolvastatásuk? Nekem természetesebb lenne, hogy van egy betöltő objektumod, és az visszaad egy paramétereket tartalmazó objektumot. Vagy ez valami lazy loading akar lenni? (Mennyi a realitása, hogy lesz olyan request, aminél egyáltalán nem lesz szükség paraméterek kiolvasására?) A loadDataFromIni meg nyilván rossz név.

A ParametersFromFile nem túl szerencsés név (inkább függvénynév lehetne), de erről már volt szó.

A loader->parser->config betöltési lánc szerintem nem életszerű, a parsolás olyan dolog, ami kimondottan egy tárolási típushoz (fájl) kapcsolódik, DB-ben vagy PHP tömbben tárolt paramétereken nincs mit parsolni. Ha úgy tetszik, a parsolás a betöltés implementációs részlete. Úgyhogy én közvetlenül a loader objektumtól várnám a paraméterek visszaadását, és a parser lehetne egy segédobjektum, amit a fileloader példányosításkor megkap (vagy maga generál a fájlnévből - ezt lehetne dependency injection containerrel, de az általában bonyolultabb, minthogy megérje vesződni vele, egyszerűbb, ha kap egy parserfactory objektumot, és az tud fájlnévből parsert generálni). Vagy ha nem akarod túlbonyolítani, akkor egyszerűen a fileparser is lehet absztrakt, és azon belül inifileparser meg mindenféle egyéb.
10

Nevek...

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 10.55
Egyre olyan érzésem van, hogy jobb, ha félreteszem mindazt, amit a Tiszta kódban olvastam és megyek a saját fejem után ilyen dolgokban. (lásd még janoszen kommentekkel kapcsolatos megjegyzése) A hosszú, részletező nevek ötlete is onnan (egy próbát megér alapon). Az eredetileg használt nevek közelebb álltak ahhoz, amit javasoltál, utólag kereszteltem át a többséget, mintegy komment helyett. :-)

Hogy a parsolás kimondottan fájlhoz tartozna? Ezzel vitatkoznék. Pl. láttam konkrétan olyan megvalósítást egy javas rendszerben, ahol egy táblában, alkalmazásonként tároltak konfigurációs adatokat, alkalmazásonként(alrendszerenként?) egy sor, soronként egy LOB, benne XMLben a szükséges konfig.
(hogy mi értelme így tárolni, nem tudom)

Ha úgy tetszik, a parsolás a betöltés implementációs részlete. Úgyhogy én közvetlenül a loader objektumtól várnám a paraméterek visszaadását,


Ezt nem értem... Nem ezt csináltam?
Szándékaim szerint a loader konstruktora kapja paraméterként a parser objektumot és egy tömbben adja vissza a kulcs/érték párokat.

upd: létezik valami "szabvány" az elnevezésekre?
8

Mi a cél?

T.G · 2012. Jún. 7. (Cs), 09.40
Mivel már sok mindent leírtak, így csak két gondolat.
Az ApplicationSetup-ban nem túl jól néz ki, a loadDataFromIni elnevezésű függvény.

Szerintem hasznos lenne, ha megírnád az XML olvasót is, és akkor könnyebben látnánk, hogy melyik kódot kell kiemelni az olvasóba és melyik maradhat az ApplicationSetup-ban. Illetve, hogy az olvasás és elemzés miként válasszuk el. De mivel mindkét irány fájl olvasást használ, talán még érdekes lehet egy adatbázisból történő olvas is. Lehet, hogy akkor már egészen másféle absztrakt osztályokat kellene gyártani. Nekem kicsit az az érzésem, hogy az ini olvasást túláltalánosítottad, ám nem biztos, hogy valóban át lett gondolva, hogy pontosan milyen általánosításokra is lesz majd későbbiekben szükség.
9

Túláltalánosított

eddig bírtam szó nélkül · 2012. Jún. 7. (Cs), 09.55
Igen, ebben egyetértünk, szerintem is.
Az elsődleges cél nem igazán egy működőképes alkalmazás létrehozása volt, inkább valami olyan, hogy mennyire tudom használni az OOP-ről eddig "megtanult" dolgokat.
Eddig az jött le, hogy lehetőleg minél apróbb darabokból, minél általánosabb megvalósítással kellene dolgozni.
A reakciókból meg az, hogy ez nincs teljesen így. :-)
28

boilerplate kód - kezdek egyre jobban belekavarodni

eddig bírtam szó nélkül · 2012. Jún. 8. (P), 08.12
Mivel nem tudtam, hogy mit jelent a boilerplate, keresgéltem.
Itt (vigyázz, ez egy PDF!) találtam egy rövid, érthetőnek tűnő magyarázatot.

És ez még jobban összezavart:
A boilerplate kód azért rossz, mert egyrészt
megsérti az információ elrejtés elvét, másrészt kiszolgáltatja az API mögötti implementációt,
hiszen egy teljes folyamat összes lépését ismerni kell, hogy használhassam.


Amikor DI-t használok, végeredményben megsértem az információ elrejtés elvét (ha jól értem), mert kívülről avatkozom az adott objektum működésébe.
Nem jól értem?
(gáz, de ez van: valami alapismeretek nagyon hiányoznak, de arról lekéstem, hogy iskolában kezdjem tanulni, használható anyagot meg mindeddig nem találtam a neten - gondolom, nem is fogok)
29

A Wikipedia szócikk korrektül

Joó Ádám · 2012. Jún. 8. (P), 13.17
A Wikipedia szócikk korrektül ismerteti, mi az a boilerplate kód.

Az információrejtés pedig mindig egyensúlyozás. A függvényparaméterezés is rontja az információrejtést.
31

OK, egyensúlyozás. De

eddig bírtam szó nélkül · 2012. Jún. 9. (Szo), 09.54
OK, egyensúlyozás. De paraméterezés kapcsán (bár a S.O.L.I.D. elveket követve a 0 paraméter az ideális, ha jól értem), azért nem mindegy, hogy feldolgozandó adatot adok át paraméterként vagy egy végrehajtó mechanizmust. Hagyományos programnyelvek esetében sohasem okozott lelki problémát az ilyesmi (pl. függvényt cím szerint átadni paraméterben, majd azt végrehajtatni), de ott nem is próbáltam ragaszkodni írásban lefektetett elvekhez.
Hogy az általam megírt kód minősége milyen volt? Passz. Kollégák tudnák megmondani, de inkább a sebességemmel voltak gondok (lásd Karway topikja "nincs kedvem dolgozni" témában!), az elkészült programjaimra nem nagyon panaszkodtak.

ui: az a baj, hogy sokszor - ebben az esetben is - már a wikipedia cikkeinek hitelességében is kételkedem, mivel úgy tűnik, egyre kevésbé ellenőrzik őket. De ha szerinted nem írnak hülyeséget, akkor elfogadom.