ugrás a tartalomhoz

Egy url-en belül több különböző értéket szeretnék átadni több különböző php-nak.

lillilla · 2014. Már. 25. (K), 20.22
Mi a teendő, ha egy url-en belül különböző értékeket szeretnék átadni GET-tel különböző fájloknak,amik egymásba vannak includeolva?

Szóval van egy index.php-m, ebbe van include-olva egy hirek.php. A menuid=4-et saját magának adja át az index.php,ettől függ, hogy melyik php-t include-olja. Az oldal=13-at pedig az include-olt hirek.php-nak szeretném átadni oldalszámként az oldal alján található lapozó linknek. A kérdés leginkább arra irányulna,hogy hogy "iktassam ki" a hirek.php lapozó linkjéből a menuid-t.
Ugye a menuid nem fix, ezért konkrét értéket nem adhatok hozzá.

Ezt próbáltam:
$oldal    = (isset($_GET['oldal'])) ? $_GET['oldal'] : 1;

$lapozo = "<p>";
$lapozo.= ($oldal <= 1) ? "Első | " : "<a href=\"{$_SERVER['REQUEST_URI']}&oldal=1\">Első</a> | ";
$lapozo.= ($oldal <= 1) ? "Előző | " : "<a href=\"{$_SERVER['REQUEST_URI']}&oldal=".($oldal-1)."\">Előző</a> | ";

for ($i=1; $i<=$oldalak; $i++) {
	$lapozo.= ($oldal == $i) ? "{$i} | " : "<a href=\"{$_SERVER['REQUEST_URI']}&oldal={$i}\">{$i}</a> | ";
}

$lapozo.= ($oldal >= $oldalak) ? "Következő | " : "<a href=\"{$_SERVER['REQUEST_URI']}&oldal=".($oldal+1)."\">Következő</a> | ";
$lapozo.= ($oldal >= $oldalak) ? "Utolsó" : "<a href=\"{$_SERVER['REQUEST_URI']}&oldal={$oldalak}\">Utolsó</a>";
$lapozo.= "</p>\n";

return $kimenet.$lapozo;
Így ezt kapom,ha rákattintok a második,majd a harmadik oldalra: index.php?m_id=6&oldal=2&oldal=3
 
1

Kód újrahasznosításához

Joó Ádám · 2014. Már. 25. (K), 20.52
Kód újrahasznosításához függvényeket használj, ne beágyazást. A kérdésednek azonban valójában nincs köze ehhez, az a bajod, hogy hozzáfűzöd az oldalszámot egy URL-hez, ami már lehet, hogy tartalmazza azt. A megoldás adja magát: karakterlánc helyett strukturált adatként kezeld az URL-eket, írj függvényt vagy osztályt a generálásukhoz.
2

Nagyon csúnya kérdés: hogyan

lillilla · 2014. Már. 25. (K), 21.24
Nagyon csúnya kérdés: hogyan írjak egy ilyen függvényt?

Van erre valami példa? Könyv? Cikk? Bármi?
3

A legegyszerűbb formájában

Joó Ádám · 2014. Már. 25. (K), 21.29
A legegyszerűbb formájában átadsz neki egy sztringet és egy asszociatív tömböt, a visszatérési érték pedig összefűzve a sztring, egy kérdőjel, majd a tömb kulcs=érték párjai &-jellel tagolva.

Ha valamelyik része nem tiszta, akkor kérdezz nyugodtan.
4

Az a legnagyobb

lillilla · 2014. Már. 25. (K), 23.14
Az a legnagyobb problémám,hogy leírod a megoldást és nem fogom fel. Én példák alapján tanulok -és tudok egyáltalán kérdezni. 2 órája ezen dühöngök,hogy így soha nem lesz belőlem programozó :( (Ebből a szempontból az agyhullám könyveket pont nekem találták ki...)
5

Függvény = function

Vilmos · 2014. Már. 26. (Sze), 00.09
Ha nem tanították, akkor itt egy leírás: PHP függvények

Egyébként a függvényt tartalmazó PHP-t célszerű külön megírni, mármint ha elég hosszú, és a fájlt inkludálni a "fő" programba. Kellemes használni, de kezdőként lesz vele gondod, ugyanis a függvényen belül nem éred el a függvényen kívül létrehozott változókat. Ugynevezett paraméterként adhatod át amire feltétlen szükséged van. Ha ez nem elég nézz utána a "global" kulcsszónak: változók globális elérése
6

Ez egy csodás leírás,

lillilla · 2014. Már. 26. (Sze), 00.58
Ez egy csodás leírás, köszönöm.
9

Nézzük akkor meg. Három

Joó Ádám · 2014. Már. 26. (Sze), 04.49
Nézzük akkor meg. Három lépésben fogjuk abszolválni a feladatot:

1. Függvényeket írunk
2. ?
3. Profit!

A Facebook, a Google és Amazon mind a fenti stratégiával készült.

A következőkben tehát egyrészt azt próbálom megmutatni, hogyan szervezd a kódot kisebb, újrahasznosítható egységekbe, másrészt hogyan kezeld megfelelően a bemenő adatokat, mert most bárki pillanatok alatt hozzáférést szerezhet bármelyik felhasználód fiókjához.

Kezdjük egy függvénnyel, amivel hozzáférünk a paraméterekhez anélkül, hogy mindig ki kellene írnunk az ellenőrzést:
function queryParameter($name) {
    if (isset($_GET[$name])) {
        return $_GET[$name];
    } else {
        return null;
    }
}
Majd folytassuk egy másikkal, ami tetszőleges értéket megkísérel egész számmá alakítani, ha pedig ez nem sikerül, akkor a második értékkel tér vissza:
function integerFrom($value, $fallback) {
    $result = $fallback;
    
    if (is_numeric($value)) {
        $result = intval($value);
    }
    
    return $result;
}
Ez lesz a kulcsa a biztonságos kódunknak, ahol számot várunk, ott valóban csak számot fogadva el, nem engedve, hogy egy támadó tetszőleges kódot írasson a kimenetre.

Jöjjön az emlegetett függvény az URL összeállításához:
function url($path, array $parameters) {
    $pairs = array();
    
    foreach ($parameters as $key => $value) {
        $pairs[] = $key . '=' . $value;
    }
    
    return $path . '?' . implode('&amp;', $pairs);
}
És akkor már egy másik, ami a linkek kiírását könnyíti meg:
function link($target, $text) {
    return '<a href="' . $target . '">' . $text . '</a>';
}
A következő pedig a megadott tömböt lemásolja, beállít rajta egy értéket, és visszaadja:
function arrayWith($name, $value, array $array) {
    $array[$name] = $value;
    return $array;
}
Jöhet a lapozó, a te logikáddal:
function pagination($numberOfPages, $activePage, $path, array $parameters) {
    $segments = array();
    
    if ($activePage <= 1) {
        $segments[] = 'Első'
        $segments[] = 'Előző'
    } else {
        $segments[] = link(url($path, arrayWith('oldal', 1,               $parameters))), 'Első');
        $segments[] = link(url($path, arrayWith('oldal', $activePage - 1, $parameters))), 'Előző');
    }
    
    for ($pageNumber = 1; $pageNumber <= $numberOfPages; $pageNumber++) {
        if ($pageNumber === $activePage) {
            $segments[] = $pageNumber;
        } else {
            $segments[] = link(url($path, arrayWith('oldal', $pageNumber, $parameters), $pageNumber));
        }
    }
    
    if ($numberOfPages <= $activePage) {
        $segments[] = 'Következő'
        $segments[] = 'Utolsó'
    } else {
        $segments[] = link(url($path, arrayWith('oldal', $activePage + 1, $parameters))), 'Következő');
        $segments[] = link(url($path, arrayWith('oldal', $numberOfPages,  $parameters))), 'Utolsó');
    }
    
    return '<p>' . implode(' | ', $segments) . '</p>';
}
És akkor tegyük össze:
$sectionId = integerFrom(queryParameter('rovat'), 1);

if (sectionExists($sectionId)) {
    $numberOfPages = numberOfPagesForSection($sectionId);
    $activePage = max(1, min(integerFrom(queryParameter('oldal'), 1), $numberOfPages));
    $path = $SERVER['PHP_SELF'];
    $parameters = arrayWith('rovat', $sectionId, array());

    echo pagination($numberOfPages, $activePage, $path, $parameters);
} else {
    die('Unknown section');
}
Figyeld meg, hogy a hibákra is felkészültünk: a felhasználótól jövő adatokat ellenőrizzük, és ha nincsenek rendben, akkor beállítunk egy alapértelmezett értéket vagy hibát írunk ki.

Az esetleges elírásokért nem vállalok felelősséget, évek óta nem fejlesztek PHP-ban, így ezt a kódot sem futtattam.

Ami a „soha nem lesz belőlem programozó” részt illeti, pár napja kaptál egy levelet, de válasz nem érkezett :)
7

Ha ez nagyjából megvan,akkor

lillilla · 2014. Már. 26. (Sze), 02.21
Ha ez nagyjából megvan,akkor hogy használjam? Mármint mire jó nekem most az,hogy van egy ilyen függvényem, mit és hogy kezdjek vele?
Mit tartalmaz az átadott string és tömb?
8

Egyszerűbben

pkadam · 2014. Már. 26. (Sze), 04.29
A gondot az okozza, hogy a $_SERVER['REQUEST_URI']-t próbálod továbbfűzni. Jelen esetben egyszerűbb, ha ehelyett felépíted az URL-t.

/*...*/ '<a href="/index.php?m_id=' . $_GET['m_id'] . '&oldal=' . $oldal /*...*/
A példában idézőjelek helyett aposztrófokat használtam, így bár egy kicsit többet kell gépelni, de áttekinthetőbb kódot eredményez: a megfelelő kódszínezővel gyorsabban észreveszed, hol vannak benne változók.

Természetesen, ha ennél bonyolultabb URL-lel van dolgod, akkor elemezheted is, pl. explode()-dal felbontod a kérdőjel mentén, majd a második felét ugyanígy, csak az &-jelek mentén. Illetve a későbbiekhez érdemes ránézned a http_build_query() függvényre is, ami a paraméterek alapján összeállítja Neked az URL kérdőjel utáni részét, megfelelően kódolva.
10

Illetve a későbbiekhez

Joó Ádám · 2014. Már. 26. (Sze), 04.53
Illetve a későbbiekhez érdemes ránézned a http_build_query() függvényre is, ami a paraméterek alapján összeállítja Neked az URL kérdőjel utáni részét, megfelelően kódolva.


Ó. Bámulatos, hol tart már a tudomány :)
11

Az egyetlen hibája az ilyen

inf · 2014. Már. 26. (Sze), 17.36
Az egyetlen hibája az ilyen jellegű megoldásoknak, hogy melegágyai az XSS-nek.
13

Lehetne csavarni

pkadam · 2014. Már. 27. (Cs), 08.59
Persze, lehetne tovább csavarni, és a $_GET['m_id'] elé (int)-et írni, htmlspecialchars()-ozni, urlencode()-olni, vagy bármi hasonlót, de ez egy lapozó lesz, és itt az érvénytelen menüazonosító már jóval korábban elvérzik, minthogy a lapozónak lehetősége lenne megjelenni.

A #12-esben tényleg elég alaposan körüljártad a kérdést, én viszont igyekeztem egy gyors és működő megoldást mutatni, amitől fennmarad a lelkesedés, és lehet egyre izgalmasabb dolgokkal folytatni. Természetesen, mivel nem ismerem a kérdezőt, lehet, hogy olyan típus, akinek a mélyebb szakmai dolgok csak jobban megmozgatják a fantáziáját, és mostanra már a SOLID utolsó betűjénél jár :) Mindenesetre a tapasztalataim alapján egy újonccal könnyebb megszerettetni a szakmát gyors és működő megoldásokkal, mert egy komplex leírástól könnyen az az érzése támadhat, hogy "ha egy egyszerű lapozóhoz ennyi minden kell, akkor mi lesz velem, ha valami bonyolultabbat szeretnék?" Talán a leggyakrabb elriasztó felállás az, amikor egyetlen sornyi kimenetért függvények serege felelős – a való életben lehet ilyen példa, de egy kezdőt megijeszthet. Sokkal szélesebb a mosoly (és akár egy kicsit gyermeki is, de ezzel nincs semmi baj), amikor meglátja, hogy egy 3 soros FOR-ciklussal megtöltheti a képernyőt. Ne azt érezze, hogy ő van a rendszernek alárendelve, hanem azt, hogy egy különleges eszköz van a kezében, amivel bámulatos dolgokat lehet véghezvinni.
14

Hát legalább az egyikünk

inf · 2014. Már. 27. (Cs), 11.18
Hát legalább az egyikünk üzenet biztos eljut hozzá... :-)
12

Ahhoz, hogy ebből egy jól

inf · 2014. Már. 26. (Sze), 21.22
Ahhoz, hogy ebből egy jól átlátható, és jól működő kódot tudj csinálni, be kell tartanod néhány alap koncepciót.

1.) Az egyik, és legfontosabb dolog, hogy a bemenetből soha semmit nem dolgozhatsz fel ellenőrizetlenül.

$oldal    = (isset($_GET['oldal'])) ? $_GET['oldal'] : 1;  
helyett

$oldal = 1;
if (isset($_GET['oldal']) && (int) $_GET['oldal']>0)
    $oldal = (int) $_GET['oldal'];
Mivel az ilyen jellegű ellenőrzéseket sokszor fogod használni, ezért célszerű osztályokat, vagy a te esetedben validációs függvényeket írni.

A függvények kód újrahasznosításra valóak, körülbelül így néz ki a fenti kód függvényekkel megadva:

$oldal = oldalSzamEllenorzes();
	
function oldalSzamEllenorzes(){
	$oldalBemenet = megletEllenorzes($_GET, 'oldal');
	$oldalSzam = sorszamEllenorzes($oldalBemenet);
	return $oldalSzam;
}
	
function megletEllenorzes(array $parameterek, $nev){
	if (isset($parameterek[$nev]))
		return $parameterek[$nev];
}

function sorszamEllenorzes($bemenet = null){
	$ertek = (int) $bemenet;
	if ($ertek < 1)
		$ertek = 1;
	return $ertek;
}
Igen, maga a kód hosszabb, de ha a függvényeket nem veszed bele, akkor ugyanúgy csak egy sor, viszont ránézésre meg tudod mondani, hogy mit csinál. A megletEllenorzes-t és a sorszamEllenorzes-t bármikor újra tudod használni más paraméterek esetében is, pl ha mondjuk valamilyen id-t vársz.

function menuSorszamEllenorzes(){
	$bemenet = megletEllenorzes($_GET, 'm_id');
	$menuId = sorszamEllenorzes($bemenet);
	return $menuId;
}
Azért nem szabad ellenőrizetlenül hagyni ezeket a paramétereket, mert a felhasználóid egy része gonosz, és beállíthat olyan értéket, amivel kárt okozhat neked, vagy a többi felhasználónak. Pl bele rakhat egy HTML kódot a $_GET['oldal']-ba, aztán küld egy linket, amit ha te vagy más megnyit, akkor lefut az a bizonyos javascript kód. Egy ilyen kóddal gyakorlatilag bármit meg lehet csinálni a nevedben, ha be vagy jelentkezve. Ha van olyan admin funkció, hogy az összes felhasználó törlése, akkor azt is megcsinálja neki az oldal. Csak rákattintasz a linkre, és az összes felhasználó törölve lesz, és fel se fogod mit történt, vagy hogy miért...

A $_SERVER['REQUEST_URI']-vel ugyanez a helyzet, azt is ellenőriznöd kell, mert a felhasználótól kapod. Annak a php fájlt választó részét a webszerver ellenőrzi helyetted, szóval azzal nem kell foglalkoznod. Elég csak leválasztanod a queryString-et róla, aztán a $_GET-ből a paraméterek ellenőrzése után újra felépíteni. Ehhez van a php-nek egy beépített url parsoló függvény, amit felhasználhatsz ellenőrzésre:

$utvonal = utvonalEllenorzes();

function utvonalEllenorzes(){
	return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
}
Ez levágja a kérdőjel utáni részt.

Nézzük meg így a kódod újra:

function lapozo($kimenet, $oldalak){
	$utvonal = utvonalEllenorzes();
	$menuId = menuSorszamEllenorzes();
	$oldal = oldalSzamEllenorzes();

	$lapozo = "<p>";  
	$lapozo.= ($oldal == 1) ? "Első | " : "<a href=\"{$utvonal}?m_id={$menuId}&oldal=1\">Első</a> | ";  
	$lapozo.= ($oldal == 1) ? "Előző | " : "<a href=\"{$utvonal}?m_id={$menuId}&oldal=".($oldal-1)."\">Előző</a> | ";  
	  
	for ($i=1; $i<=$oldalak; $i++) {  
		$lapozo.= ($oldal == $i) ? "{$i} | " : "<a href=\"{$utvonal}?m_id={$menuId}&oldal={$i}\">{$i}</a> | ";  
	}  
	  
	$lapozo.= ($oldal >= $oldalak) ? "Következő | " : "<a href=\"{$utvonal}?m_id={$menuId}&oldal=".($oldal+1)."\">Következő</a> | ";  
	$lapozo.= ($oldal >= $oldalak) ? "Utolsó" : "<a href=\"{$utvonal}?m_id={$menuId}&oldal={$oldalak}\">Utolsó</a>";  
	$lapozo.= "</p>\n";  
	  
	return $kimenet.$lapozo;  
}
Mint az látható, nincs benne egy deka $_SERVER és $_GET sem, ami jó. Feltételeztem, hogy egy lapozo függvényben van a kód, amit adtál...

2.) Egy másik koncepció, amit meg kell értened, azt úgy hívják, hogy dependency injection. Ez körülbelül arról szól, hogyha újrahasznosítható kódot akarsz, akkor a kód függőségeit mindig be kell injektálnod, és nem helyben létrehoznod. Jelen esetben ennek egy lebutított változatáról van szó, ha azt akarod, hogy csak egyszer kelljen kell megírni a lapozo függvényedet, és ne kelljen mondjuk copy-paste-elni, akkor úgy kell megcsinálnod, hogy paraméterezhető legyen. Miért nem jó copy-paste-elni? Azért, mert ha később módosítani akarod, a lapozód kinézetét, vagy bármi mást, akkor minden egyes helyet meg kell keresned, ahova odamásoltad a lapozót, és egyesével mindegyiket módosítanod. Ha viszont egyetlen helyen van a lapozo függvényed, akkor ha belenyúlsz, az az összes olyan oldalon módosítani fogja a lapozó kinézetét, ahol használod.

Egy kicsit csaltam ezzel a szabállyal kapcsolatban az ellenőrző függvények egy részénél. Ha megnézed egy az egyben $_GET-et és $_SERVER-t, illetve string konstansokat, mint 'REQUEST_URI', 'oldal', 'm_id' használok, amiknek függvény paramétereknek kellene lenniük. Ennek az az oka, hogy nem akartam egy teljesen általános ellenőrző keretrendszert írni, sem objektum orientált kódot adni...

Térjünk vissza a lapozo függvényedhez. Jelen esetben milyen további függvény paraméterek lehetnek?

Nyilván azok, amiket ellenőrzünk az elején ($utvonal, $menuId, $oldal), mert azok mind a felhasználói bemenetből jönnek. A $kimenet és $oldalak, amik meg már alapból ott vannak paraméternek a lapozóhoz. Más nem igazán van. Szóval az ellenőrző kódrészeket ki kell helyezned a függvényen kívülre, és paraméterként megadnod őket.

$utvonal = utvonalEllenorzes();
$menuId = menuSorszamEllenorzes();
$oldal = oldalSzamEllenorzes();

$kimenet = lapozo($kimenet, $utvonal, $menuId, $oldal, $oldalak);
	
function lapozo($kimenet, $utvonal, $menuId, $oldal, $oldalak){
	...
}
Előfordulhat, hogy a $menuId mellett még mást is akarsz $_GET-ben küldeni, szóval jobb, ha a $utvonal és a $menuId helyett ezek összefűzött változatát adod át:

$utvonal = utvonalEllenorzes();
$menuId = menuSorszamEllenorzes();

$urlTorzs = $utvonal.'?m_id='.$menuId;
$oldal = oldalSzamEllenorzes();

$kimenet = lapozo($kimenet, $urlTorzs, $oldal, $oldalak);
	
function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$lapozo = "<p>";  
	$lapozo.= ($oldal == 1) ? "Első | " : "<a href=\"{$urlTorzs}&oldal=1\">Első</a> | ";  
	$lapozo.= ($oldal == 1) ? "Előző | " : "<a href=\"{$urlTorzs}&oldal=".($oldal-1)."\">Előző</a> | ";  
	  
	for ($i=1; $i<=$oldalak; $i++) {  
		$lapozo.= ($oldal == $i) ? "{$i} | " : "<a href=\"{$urlTorzs}&oldal={$i}\">{$i}</a> | ";  
	}  
	  
	$lapozo.= ($oldal >= $oldalak) ? "Következő | " : "<a href=\"{$urlTorzs}&oldal=".($oldal+1)."\">Következő</a> | ";  
	$lapozo.= ($oldal >= $oldalak) ? "Utolsó" : "<a href=\"{$urlTorzs}&oldal={$oldalak}\">Utolsó</a>";  
	$lapozo.= "</p>\n";  
	  
	return $kimenet.$lapozo;  
}

Haladjunk tovább...

3.) További koncepció, hogyha látsz egy ismétlődő mintát a kódodban, akkor azt újra tudod hasznosítani úgy, hogy kiemeled egy változóba vagy egy függvénybe. Például az ellenőrzéseknél és most az $urlTorzs átadásánál is volt egy ilyen kód újrahasznosító mellékhatása a módosításainknak.

Nézzük meg a mostani kódot. Az alábbi minta nagyon sokszor ismétlődik benne:

	$lapozo.= $kizaroFeltetel ? ($cim.$elvalaszto) : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";  
Ezt egy az egyben ki tudjuk emelni egy függvénybe:

function lapozoLink($kizaroFeltetel, $cim, $elvalaszto, $urlTorzs, $oldal){
	return $kizaroFeltetel ? ($cim.$elvalaszto) : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";
}
Nézzük meg hogy módosul ettől a kódunk:

$utvonal = utvonalEllenorzes();
$menuId = menuSorszamEllenorzes();

$urlTorzs = $utvonal.'?m_id='.$menuId;
$oldal = oldalSzamEllenorzes();

$kimenet = lapozo($kimenet, $urlTorzs, $oldal, $oldalak);
	
function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', ' | ', $urlTorzs, 1);
	$lapozo.= lapozoLink($oldal == 1, 'Előző', ' | ', $urlTorzs, $oldal-1);
	
	for ($i=1; $i<=$oldalak; $i++)
		$lapozo.= lapozoLink($oldal == $i, (string) $i, ' | ', $urlTorzs, $i);
	
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Következő', ' | ', $urlTorzs, $oldal+1);
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Utolsó', ' | ', $urlTorzs, $oldalak);
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}
Felfedezhetünk egy további ismétlődő mintát, a ' | ' elválasztót minden linknek átadjuk. Ilyenkor azt csinálhatjuk, hogy, változónak vagy konstansnak adjuk értékül, és így újrahasznosítjuk a string létrehozás mintáját.

$elvalaszto = ' | ';
Ha ez megvan, akkor elgondolkodhatunk azon, hogy hova tesszük ezt a változót. Erre három variáció van jelen esetben:

a.)

function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';
	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', $elvalaszto, $urlTorzs, 1);
	...
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}

function lapozoLink($kizaroFeltetel, $cim, $elvalaszto, $urlTorzs, $oldal){
	return $kizaroFeltetel ? ($cim.$elvalaszto) : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";
}
b.)

function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', $urlTorzs, 1);
	...
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}

function lapozoLink($kizaroFeltetel, $cim, $urlTorzs, $oldal){
	$elvalaszto = ' | ';
	return $kizaroFeltetel ? ($cim.$elvalaszto) : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";
}
c.)

function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';

	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', $urlTorzs, 1);
	$lapozo.= $elvalaszto;

	...
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}

function lapozoLink($kizaroFeltetel, $cim, $urlTorzs, $oldal){
	return $kizaroFeltetel ? $cim : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>";
}
Én a c.)-t javaslom, mert azzal kétféle ismétlődést ki lehet váltani. Az egyik a $elvalaszto létrehozásának vagy átadásának ismétlődése, a másik pedig a lapozoLink kódjában a $elvalaszto hozzáfűzésének az ismétlődése. Nem tudom, hogy észrevetted e, de ott is volt egy ismétlődő minta. Megmutatom részletesebben:

c.1.)

function lapozoLink($kizaroFeltetel, $cim, $elvalaszto, $urlTorzs, $oldal){
	return $kizaroFeltetel ? ($cim.$elvalaszto) : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";
}
c.2.)

function lapozoLink($kizaroFeltetel, $cim, $elvalaszto, $urlTorzs, $oldal){
	if ($kizaroFeltetel)
		return $cim.$elvalaszto;
	else
		return "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>{$elvalaszto}";
}
c.3.)

function lapozoLink($kizaroFeltetel, $cim, $elvalaszto, $urlTorzs, $oldal){
	$link = '';
	if ($kizaroFeltetel)
		$link.= $cim;
	else
		$link.= "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>";
	$link.= $elvalaszto;
	return $link;
}
c.4.)

function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';

	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', $urlTorzs, 1);
	$lapozo.= $elvalaszto;

	...
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}

function lapozoLink($kizaroFeltetel, $cim, $urlTorzs, $oldal){
	return $kizaroFeltetel ? $cim : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>";
}
Ezt hívják refaktorálásnak, amikor egy kódot átláthatóbb formára alakítasz úgy, hogy közben a viselkedése semmit sem változik.

Itt látszik, hogy az $elvalaszto hozzáfűzése nem feltétlen kell, hogy a lapozoLink gyártás része legyen, sokkal inkább a lapozo-hoz tartozik ez a feladat, így átemelhetjük a lapozóba. Ezt úgy is hívják, hogy magasabb absztrakciós szintre emelés, amikor egy függvényből az őt hívó másik függvénybe emelünk át kódot azért, mert inkább oda tartozik logikailag.

4.) A további koncepció, amit fontos betartani az a single responsibility principle. Ez körülbelül a te esetedben annyit tesz, hogy egy kód részletnek egy adott feladatra kell szakosodnia, nem keverhetünk logikailag dolgokat. Ezt már érintettük az előző magasabb absztrakciós szintre emeléssel, amikor azt mondtuk, hogy az $elvalaszto hozzáfűzése a lapozóhoz nem a lapozoLink hatásköre, hanem a lapozo építő függvényünké.

Nézzük meg a mostani kódot, hogy találunk e hasonló mintát benne?

function lapozo($kimenet, $urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';

	$lapozo = "<p>";  
	$lapozo.= lapozoLink($oldal == 1, 'Első', $urlTorzs, 1);
	$lapozo.= $elvalaszto;
	
	$lapozo.= lapozoLink($oldal == 1, 'Előző', $urlTorzs, $oldal-1);
	$lapozo.= $elvalaszto;
	
	for ($i=1; $i<=$oldalak; $i++) {
		$lapozo.= lapozoLink($oldal == $i, (string) $i, $urlTorzs, $i);
		$lapozo.= $elvalaszto;
	}
	
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Következő', $urlTorzs, $oldal+1);
	$lapozo.= $elvalaszto;
	
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Utolsó', $urlTorzs, $oldalak);
	$lapozo.= $elvalaszto;
	
	$lapozo.= "</p>\n";  
	
	return $kimenet.$lapozo;  
}
A $lapozo hozzáfűzése a $kimenet-hez például ilyen. Ahhoz, hogy gyártsunk bármilyen oldalra lapozót teljesen felesleges tudnunk arról, hogy egyáltalán létezik a $kimenet, amihez hozzá akarjuk fűzni. Mi csak egy lapozót akarunk csináltatni HTML formában a függvényünkkel, semmi többet. Egyébként abból is látni, hogy gond van, hogy $kiemenet = lapozo($kiement, ...); szóval hogy a $kimenetet átadjuk paraméterként és vissza is kapjuk. Ez nem egy megszokott minta jó minőségű kódnál. Emeljük tehát magasabb absztrakciós szintre a $kimenet-hez a $lapozo-t hozzáfűző kódrészt:

$utvonal = utvonalEllenorzes();
$menuId = menuSorszamEllenorzes();

$urlTorzs = $utvonal.'?m_id='.$menuId;
$oldal = oldalSzamEllenorzes();

$kimenet.= lapozo($urlTorzs, $oldal, $oldalak);

function lapozo($urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';

	$lapozo = "<p>";  
	...
	$lapozo.= "</p>\n";  
	
	return $lapozo;
}
Összesítő:

A kódod az összes refaktorálás után tehát így néz ki:

$utvonal = utvonalEllenorzes();
$menuId = menuSorszamEllenorzes();

$urlTorzs = $utvonal.'?m_id='.$menuId;
$oldal = oldalSzamEllenorzes();

$kimenet.= lapozo($urlTorzs, $oldal, $oldalak);


function utvonalEllenorzes(){
	return parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
}

function menuSorszamEllenorzes(){
	$bemenet = megletEllenorzes($_GET, 'm_id');
	$menuId = sorszamEllenorzes($bemenet);
	return $menuId;
}

function oldalSzamEllenorzes(){
	$oldalBemenet = megletEllenorzes($_GET, 'oldal');
	$oldalSzam = sorszamEllenorzes($oldalBemenet);
	return $oldalSzam;
}
	
function megletEllenorzes(array $parameterek, $nev){
	if (isset($parameterek[$nev]))
		return $parameterek[$nev];
}

function sorszamEllenorzes($bemenet = null){
	$ertek = (int) $bemenet;
	if ($ertek < 1)
		$ertek = 1;
	return $ertek;
}

function lapozo($urlTorzs, $oldal, $oldalak){
	$elvalaszto = ' | ';

	$lapozo = "<p>";  

	$lapozo.= lapozoLink($oldal == 1, 'Első', $urlTorzs, 1);
	$lapozo.= $elvalaszto;
	
	$lapozo.= lapozoLink($oldal == 1, 'Előző', $urlTorzs, $oldal-1);
	$lapozo.= $elvalaszto;
	
	for ($i=1; $i<=$oldalak; $i++) {
		$lapozo.= lapozoLink($oldal == $i, (string) $i, $urlTorzs, $i);
		$lapozo.= $elvalaszto;
	}
	
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Következő', $urlTorzs, $oldal+1);
	$lapozo.= $elvalaszto;
	
	$lapozo.= lapozoLink($oldal >= $oldalak, 'Utolsó', $urlTorzs, $oldalak);
	$lapozo.= $elvalaszto;
	
	$lapozo.= "</p>\n";  
	
	return $lapozo;
}

function lapozoLink($kizaroFeltetel, $cim, $urlTorzs, $oldal){
	return $kizaroFeltetel ? $cim : "<a href=\"{$urlTorzs}&oldal={$oldal}\">{$cim}</a>";
}


Most jelenleg nagyjából minden a helyén van ebben a kódrészletben, de ha megnézed a menuSorszamEllenorzes-t és az oldalSzamEllenorzes-t, már most is felfedezhetsz egy ismétlődő mintát. A sorszamEllenorzes-ből ki lehet emelni egy egeszSzamEllenorzes-t. Ha megnézed a $kizaroFeltetel-t, akkor azon is látszik, hogy magasabb absztrakciós szintre kell emelni vagy legalább az ellentettjét venni pl $aktivLink néven, mert így nehezebben értelmezhető, illetve a lapozo kódjánál is lehetne implode-ot használni string összefűzésre, és így tovább... Ha refaktorálod a többi kódodat is, akkor újra találni fogsz emellé még egy csomó ismétlődő kódrészt, amit a kód újrahasznosítás miatt kitehetsz a saját függvényeidbe. Átgondolhatod, hogy melyik függvényednek mi legyen a feladata, és mozgathatod közöttük a kódrészleteket. Túlzásba sem szabad vinni, csak az ismétlődő kódrészletekre koncentrálj, ne kövesd el azt a hibát, hogy olyan dolgokra írsz általános érvényű kódot, amiket a jelenlegi kódod egyáltalán nem használ, ezt overengineering-nek hívják. Ha általános kódot akarsz használni, akkor keress kész keretrendszereket, ezeket olyanok írják, akiknek sokkal több tapasztalatuk van a témában. Érdemes használni őket, egy csomó munkát meg lehet spórolni velük, cserébe viszont legalább egyszer meg kell tanulnod a használatukat, ami egy bonyolult keretrendszernél sok időbe kerülhet. Ha valami egyszerűbb problémára keresel megoldást, mint mondjuk ez a lapozás, akkor rengeteg ingyenes kódot találsz rá google-ben. Lehet használni ezeket is, de azért érdemes fenntartásokkal élni, és belenézni a kódjukba, mert az nem feltétlen jó minőségű...

Ja és ha komolyan programozni akarsz, akkor tanulj meg angolul, ha meg php-ban akarsz létrehozni, akkor használd a php manual-t, mert abban is rengeteg hasznos függvény van, amit használhatsz. Nem kell feltalálni a spanyol viaszt...
15

Teendő hiba esetén ?

Vilmos · 2014. Már. 27. (Cs), 13.37
Láttam már tőled néhány elgondolkodtató levezetést, ebben is sok munka van, gratulálok!
Mégis ... ne vedd zokon, ezzel a szemlélettel, a feltétel nélküli hibatűréssel nekem már sok gondom volt. Hogy is fogalmazzak ...

Van egy komplex függvény készlet ami ellenőriz/feldolgoz egy elfogadható vagy véletlenül/szándékosan elrontott adathalmazt. Elvileg jó, viszont ebben a formában pont a szűrendő hibákra érzékeny (a hatás kiszámíthatatlan). Nem kívánt adat esetén a függvények belső hibáit fogjuk elsősorban nyomozni, mert az "error" a forrástól nagy távolságban bukkan majd fel. Gondolom, nem szándékosan ilyen, csak sajnos automatikusan erre az eredményre jutunk amennyiben a hibakezelés fel sem merül.

Mi történik ha nincs érvényes paraméter? Konkrétan - megletEllenorzes() - bízzuk magunkat a PHP-ra majd csak generál egy üres sztringet, mivel return az éppen nincs. Valószínűleg nem akadunk ki, egyszerű az eset is, hamar rájövünk mit tettünk. Túl sok infóra azért nem számíthatunk.

Úgy gondolom, sok időt takarítunk meg, ha némi paranoiával szemléljük becses függvényeinket. Lehetséges hibaforrások azok is. Gyorsan megírva erre mérget vehetsz.
Ha már kezdőnek adunk tanácsot, szerintem jobban jár primitívebb megoldással, de beépített hibaüzenettel. Ezt fontosabbnak tartom mint ez elegáns megjelenést. (az URL építést szándékosan kihagytam):

  define('TESZT','teszt');   // Teszt kornyezet

  $m_id = 0;
  if ( isset( $_GET['m_id']) 
    { $m_id = (integer)$_GET['m_id'] ;}

  switch ( $m_id ){
  case 0:
    if (defined('TESZT')) {
       echo '<pre>'; 
       echo isset( $_GET['m_id'] );
       echo $_GET['m_id']; 
       echo '</pre>'; 
    }
    break; 

  case 1:
    lapozo( $m_id );
    break;
  }
16

Mi történik ha nincs érvényes

inf · 2014. Már. 27. (Cs), 15.28
Mi történik ha nincs érvényes paraméter? Konkrétan - megletEllenorzes() - bízzuk magunkat a PHP-ra majd csak generál egy üres sztringet, mivel return az éppen nincs. Valószínűleg nem akadunk ki, egyszerű az eset is, hamar rájövünk mit tettünk. Túl sok infóra azért nem számíthatunk.


A megletEllenorzes() jelen esetben opcionális paraméterekre van kiélezve, mert kötelező paraméter nem volt a kódrészletben. Ha van kötelező paraméter, akkor ki kell egészíteni az ahhoz kapcsolódó kóddal valahogy így:

function megletEllenorzes(array $parameterek, $nev, $kotelezo = false){  
    if (isset($parameterek[$nev]))  
        return $parameterek[$nev];
    else if ($kotelezo)
        throw new Exception("A {$nev} paramétert kötelező megadni.");
}  
Mondjuk ha a menü id megadása kötelező lenne, akkor ilyen lenne a használata:

function menuSorszamEllenorzes(){  
    $bemenet = megletEllenorzes($_GET, 'm_id', true);  
    $menuId = sorszamEllenorzes($bemenet);  
    return $menuId;  
} 
Ha már kezdőnek adunk tanácsot, szerintem jobban jár primitívebb megoldással, de beépített hibaüzenettel. Ezt fontosabbnak tartom mint ez elegáns megjelenést.


Hibakezelés szempontjából a kód ismétlések megakadályozása az általad "elegáns megjelenésnek" titulált módszerekkel sokkal fontosabb, mint a "debug mode", és nem "teszt környezet" írása, amit te javasolsz. A debug elősegítése a te módszereiddel overengineering-nek számít és kerülendő, hibás elképzelés. A stack trace használata és a hibák visszakeresése viszonylag jól működő dolog, de összességében bárhonnan is futunk neki a debuggolásnak, az eredmény mindig hibáktól hemzsegő kód lesz. Az utólagos tesztelés helyett a kódokat előre kell tesztelni még a megírásuk előtt...

Jelen esetben a teszteket előre kellett volna megírnom valamilyen teszt keretrendszer, pl phpunit használatával, és csak utána módosítanom a kódot, mert a tesztek nélküli refaktorálás könnyen hibákhoz vezethet. Nálam is vezetett, utólag észrevettem, kijavítottam... A bevezetést a phpunit használatába túlzásnak tartottam, ezért nem írtam bele, így is túl hosszúra sikeredett a hozzászólás... Lehet, hogy a későbbiekben írok bevezetés a programozásba jellegű könyvet, vagy cikkeket, majd még meglátom mennyire lesz kedvem hozzá...
17

Nem gondoltam bonyolult

Vilmos · 2014. Már. 27. (Cs), 17.33
Nem gondoltam bonyolult eseménykezelésre. Van egy több lapból álló oldal, az elsőt előállíjuk PHP-val, illetve a böngészőből megfelelő kattintással - szerver oldal hívása után - szintén PHP-val egy másikat. Nos, itt a belépési pontok két helyen is léteznek. Egyrészt a HTML szövegben, másrészt a tükörképe a PHP-ban írt vezérlőben.
Miért tekinted gondnak ebben a speciális esetben, ha figyelmeztetünk egy lehetséges hibás hívásra? Az üres oldal informatívabb? Vagy még jobb, egy távoli függvény hibát dob, mert problémája akadt aminek okát pár szinttel feljebb kell majd keresgélni. Persze előre tudjuk milyen intervallumot várunk, de van egy általánosított és utólag kiokosított függvényünk ami csak saját magával foglalkozik. És ez jó, mert nincs túltervezve. Teszteléshez pedig mindenképp használjunk (x)debug-ot.

"Stack trace", azt hiszem tudom miről beszélsz, bár ez a szleng ismeretlen. A javasolt függvényeidre hogyan kapcsolod be? Vagy ez is if-else blokkban játszik mint az ajnározott throw-exception? Remélem tanulhatok valamit ez ügyben.
18

"Stack trace", azt hiszem

inf · 2014. Már. 27. (Cs), 19.18
"Stack trace", azt hiszem tudom miről beszélsz, bár ez a szleng ismeretlen.


Az előzményeket tartalmazza, hogy hogyan került meghívásra a hibát kiváltó függvény. Ha jól tudom (bár ennek nem néztem utána) a php-ben az exception-nél automatikusan kiírja az error esetében viszont a set_error_handler és a debug_backtrace kombinációjával vagy xdebug használatával lehet megtudni. Én általában mindenre kivételt dobok, úgyhogy nem nagyon futok bele olyan helyzetbe, hogy ne lenne alapból kint. A kivételkezelés-nek kellene utánanézned, azzal sokkal jobban lehet hibákat kezelni php-ben, mint bárhogy máshogy.

Miért tekinted gondnak ebben a speciális esetben, ha figyelmeztetünk egy lehetséges hibás hívásra?

A kódot akkor írjuk meg, amikor szükség van rá, nem akkor, amikor azt feltételezzük, hogy talán egyszer szükség lehet rá, ezért overengineering. Ha azt akarod, hogy kevesebb hiba legyen a kódodban, akkor írj hozzá teszteket ahelyett, hogy a hibákat próbálod lenyomozni...
A másik, ami miatt hibás az elképzelés, hogy sérti a single responsibility principle-t, a függvényednek nem lehet két feladata. Vagy tesztel, vagy végrehajt valamit, a kettő együtt nem megy.
19

overengineering és egyebek

Vilmos · 2014. Már. 28. (P), 10.43
( Túltervezés = túlméretezés. Szükséges rossz. A programozásban kiforgatták a fogalmat, inkább azt értik rajta hogy mással foglalkozol mint amivel kellene. )

Szerintem akkor van kevesebb hiba a kódban, ha egyszerűsített feltételek között működik.

A külső inputra nem ugyanaz vonatkozik mint a "védett" adatra. Alapértelmezésben megbízható helyről származik (nem biztos), tartalmilag jó (jobbára), a küldőnek megfelelt (nekünk esetleg). A bizonytalanság miatt ellenőrizni lehet/kell az inputokat. Azt nem tudom megvizsgálni hányféleképpen lehet elrontani, arról van elképzelésem miféle adattal működik helyesen egy konkrét függvény. Valahogy így szoktam eljárni:

if ( check_params()) {
   lapozo();
}
Ez persze nem általánosítható, de vannak esetek amikor jobb mint a tesztek írása. Egyébként nem mondtam, hogy a vizsgálatokat a függvények belsejében kell elhelyezni.

A "kivétel dobás" megsérti az elveket amikre hivatkozol. Egyértelműen túltervezés. Nem csináltál előzetes vizsgálatot, emiatt a hibák szabadon terjednek a rendszerben. Mutációként jelentkeznek a kölcsönhatások miatt. Csak a legvégső ponton fogod meg. Ott viszont annyiszor ahány részre sikerült szétszedni a feladatot. Külön bónusz, sikeresen létrehoztál egy "aspektus orientált" feladatot.
Egyik függvényednek sem feladata a hibakezelés, mégis belekerült. Hány feladatuk van ténylegesen?
Alighanem a neveltetésem miatt nem megyek bele ilyen megoldásokba. Inkább ellenőrzök munka előtt, azután lesz ami lesz. A tesztelés gondja kideríteni mi maradt ki.

Ui.
Az tetszik a programozási elvekben, főleg az OOP elvekben, hogy paradoxonokban gondolkodik. Talán így van ez jól. TED video
Például: A többalakúság a rugalmasság feltétele, sajnos örökléssel jutunk hozzá ami rugalmatlanná teszi a kódot. Az objektum összetétel, a láncolás (DI), hatékonyabb az öröklésnél, és teljesen rugalmas. Azonnal mellékelik hozzá "Demetert" ami kimondja, a láncolás rugalmatlan és a hossza módfelett aggályos.
20

A kivételt bármikor

inf · 2014. Már. 28. (P), 11.35
A kivételt bármikor elkaphatod, amikor csak akarod, senki nem kötelez rá, hogy csak egy helyen tedd. A hibakezelés a hibák elkapását jelenti, és nem a hibák kiváltását, szóval ha kivétel dobó kód van egy függvényben, az nem sérti az SRP-t, egyszerűen csak azt jelzi, hogy a függvény valami miatt nem tudta ellátni a feladatát. A teszteket integrálni a kódodba marhaság.

A többalakúságot el lehet érni objektum összetétellel, aminek semmi köze a láncoláshoz. A láncolás is csak bizonyos esetekben tiltott a Demeter trv által, ha sérti az adatrejtést, pl a fluent interface megengedett. Olvashatóság szempontjából is csak akkor rossz, ha nincs rengesen eltördelve a pontok mentén, és rossz a behúzása.

Összességében ahogy nézem mindent keversz mindennel.
22

"Bármikor"

Vilmos · 2014. Már. 28. (P), 15.09
Hát ez az. Hová kerüljön kivétel, és miért? Ahogy a teszt adta vagy pillanatnyi programozói kényelem. Ahol van, az a legrondább "debug kód" amit el tudok képzelni. Az egész függvénytörzs egyetlen nagy "if", valahol messze-messze "else" után a kiugrás.
Egy biztos, józan ész szerint akkor írható kivételes kiugrálás ha annak semmi, abszolút semmi káros következménye nincs.

Igen, keverek sok mindent. A konkurens mémek (módszerek stb.), véletlen sem alkotnak egységes rendszert. Egyszer szeretnék látni valami kimutatást, melyek szimbióták, melyek dolgoznak egymás ellen. Végül is a területszerzés egy másik ideológia rovására folyik. Most csak úgy érzésre válogatok.
31

Ahol van, az a legrondább

inf · 2014. Már. 28. (P), 21.04
Ahol van, az a legrondább "debug kód" amit el tudok képzelni. Az egész függvénytörzs egyetlen nagy "if", valahol messze-messze "else" után a kiugrás.

Hát ezen jót röhögtem :D Az egész függvénytörzs, amiről beszélünk 4 soros...

De ha ennyire számít, hogy a függvény elején legyen a bemenet ellenőrzése, akkor parancsolj.

function megletEllenorzes(array $parameterek, $nev, $kotelezo = false){   
	$megadva = isset($parameterek[$nev]);
	if ($kotelezo && !$megadva)   
		throw new Exception("A {$nev} paramétert kötelező megadni.");  
	if ($megadva)  
		return $parameterek[$nev];  
}    
32

Majd egyszer elmagyarázod mit

Vilmos · 2014. Már. 28. (P), 23.50
Majd egyszer elmagyarázod mit csinálsz. Önerőből. A kérdezés mindig valami cselezéshez vezet nálad. Ez a kivétel mégis mi célt szolgál? Nem teszt ugyebár, szerinted. A hiba nem kezelhető le így sem, egyetértünk. Leginkább divat, szerintem.

Viszlát
21

A kódot akkor írjuk meg,

Hidvégi Gábor · 2014. Már. 28. (P), 13.19
A kódot akkor írjuk meg, amikor szükség van rá, nem akkor, amikor azt feltételezzük, hogy talán egyszer szükség lehet rá, ezért overengineering.
Nos, lehet, hogy félreértem, de ez pont ellentétben van azzal, amit tegnap írtál. Az eredeti kérdésem ez volt:
»Nem lesz így túlságosan elbonyolítva a kód? Nem lesznek túlságosan elbonyolítva a tesztek? Mekkora projektnél van szükség ilyen szintű absztrakcióra?«
És a válasz tőled:
Bármekkoránál, ha úgy látod, hogy később fejlesztések lesznek, hozzá kell nyúlni, stb... Egy ilyen rendszerben bármikor lecserélheted az összes modulodat, ha tartod a határfelület struktúráját, ami közöttük van. Pl bármikor hozzáadhatok egy másik storage modult, ami fájlrendszerbe, adatbázisba, memory-ba ment, esetleg cookie-ba ment, stb...


A jelenlegi legnagyobb munkámban tanultam meg, hogy az egyszerűségre való törekvés a legkifizetődőbb. Lecserélhetem a modulokat, de mi van, ha nem lesz erre szükség? Mi van akkor, ha közben elfogy a pénz, és becsődöl az egész? Miért legyen a kód ennyire absztrakt?

Olvasgatok a különböző programozási paradigmákról, és úgy látom, hogy mindegyik mellett párhuzamosan új problémák jelennek meg, amik tovább bonyolítják a helyzetet:

- Dolgozzunk OOP-ben! Hát ez így nem elégséges, be kell vezetni az OOP mintákat, mert anélkül nem lesz hatékony.
- Írjunk teszteket! De ez így nem elég, írjuk meg őket előbb, aztán csak magát a kódot. Ha később a program változik, a teszteket is akár írhatom újra. Nem mindegy, hogyan írom meg a teszteket, az egyes modulok közti összefüggéseket csökkenteni kell. Node a végső kódban a modulok egymással dolgoznak!
- És így tovább.

Valóban szükség van ilyen szintű bonyolításra?
23

A tudásnak nincs határa

Vilmos · 2014. Már. 28. (P), 15.19
Új megoldások új gondokkal járnak. Azt hiszem még nem találtak kivételt. A tudomány világában ez elfogadott, az informatikában még nem?
24

Új megoldások

Hidvégi Gábor · 2014. Már. 28. (P), 15.33
Pontosan milyen problémát oldanak ezek meg?
25

- Design patterns: Erről már

BlaZe · 2014. Már. 28. (P), 15.53
- Design patterns: Erről már volt szó sokszor, illetve inf3rno le is írta. Sokkal könnyebben karbantartható a kód az ilyen megoldásoktól. Hogy ezeket aztán nevesítette a szakma és kaptak valamilyen pattern nevet, az meg ennek a következménye. Plusz a karbantarthatóság mellett fontos szempont a tesztelhetőség. Egy erős csatolású egymást hívó kódhalmot nem tudsz normálisan/izoláltan tesztelni.
- TDD: Hogy néz ki egy fejlesztés? Valaki definiálja a feladatot, tehát tudod az alkalmazás melyik részeitől milyen viselkedést vársz el. Erre írod meg a tesztet, majd a teszttel validálod az implementációt és iterálsz mindaddig, amíg nem az elvárt viselkedést hozza. Nem értem ezzel mi a bajod. Ezt csinálod MINDIG. Akkor is, ha nincs teszted előre. Csak akkor "szemmel", ergo könnyebben viszel be bugokat. És elfelejted, kiesel a kontextből, nem tudsz pár szempillantás alatt levalidálni nagy halom kódot, ergo sokkal később fogod látni, hogy valami nem jó... Miért az a túlbonyolítás, ahol ezek a feltételek már az implementáció megkezdésekor adottak?
26

Félreérthető voltam, most nem

Hidvégi Gábor · 2014. Már. 28. (P), 16.39
Félreérthető voltam, most nem közvetlenül a Design Patterns és a TDD volt a célkeresztben, hanem arra szerettem volna rámutatni, hogy ezek a metódusok újabb bonyolultságot hoznak be a kódba, ráadásul egyiknek sem egyértelmű a használata, mint ahogy a Boundaries blogmark is rámutat, vagy például a singleton mintát sem ajánlják sok helyen. Az absztrakciók szivárognak, minél több van, annál jobban.

Továbbá felmerülhet az emberben, hogy mennyire lehet progresszív: amikor kijön egy új paradigma, érdemes-e mindjárt kipróbálni, vagy inkább várjak pár évet, mire kiforrja magát?
27

Szerintem ezen nem érdemes

BlaZe · 2014. Már. 28. (P), 17.43
Szerintem ezen nem érdemes ennyit lamentálni :) A programozás önmagában bonyolult és tapasztalat kell hozzá, hogy legalább többségében a jó megoldásokat találd meg. Mindig úgyse sikerül. Ezért is fontos olyan módszerek alkalmazása, amik segítenek a későbbi igazításban (pl laza csatolás, tesztek, code review).
28

Én amellett vagyok, hogy ki

inf · 2014. Már. 28. (P), 20.24
Én amellett vagyok, hogy ki kell próbálni, aztán vagy tetszik, vagy nem. Nekem pl a trendi dolgok közül a REST bejön a DDD, hexagonal architecture, meg egyebek, amit mostanában nyomatnak már kevésbé, én inkább modulokban gondolkodom, amik egyenrangúak, mint rétegekben, amik egymásra épülnek.
29

Bármekkoránál, ha úgy látod,

inf · 2014. Már. 28. (P), 20.46
Bármekkoránál, ha úgy látod, hogy később fejlesztések lesznek, hozzá kell nyúlni, stb...

Jó, akkor pontosítok rajta, most éppen release early, release often szerint próbálok fejleszteni. Szóval kitűztem egy nagyon rövid távú célt, viszont eleve erre a rendszerre építkezem már ennél a rövidtávú célnál is, mert látom, hogy még rengeteg más modul is bele fog kerülni a rendszerbe a többi release-nél, és nincs kedvem a későbbiekben tök fölöslegesen refaktorálni az egészet az alapoktól. Ilyen kontextusban gondoltam. Ha tudod, hogy csak egy kis weboldal lesz, amihez nem kell a későbbiekben hozzányúlni, akkor nyilván nem szórakozol egy ilyen rendszer felépítésével, mert minek...

Lecserélhetem a modulokat, de mi van, ha nem lesz erre szükség?


Egyébként szerintem még a kisebb projekteknél is van értelme mindent modulokra bontani, és modul szintű teszteket írni, mert sokkal könnyebben megy úgy a fejlesztés, mintha az egészet akarnád egyben megírni. Nekem pl sokkal kényelmesebb így, hogy nem kell foglalkoznom az sql-el a projekt elején, elég csak kimockolnom az ehhez tartozó modult, és szevasz. Szóval nekem szükségem van egy ilyen rendszerre, mert segít koncentrálni a lényegesebb dolgokra. Nem véletlenül írtam, vagy csak passzióból, mert megtehetem. Lehet, hogy neked mások az igényeid, de ez már nem az én dolgom...

Miért legyen a kód ennyire absztrakt?

Nem tudom mi absztrakt neked ebben. Nekem nagyon is kézzelfogható. Vannak modulok meghatározott céllal, pl adattárolás, amik ehhez a célhoz kapcsolódó objektumokat szolgáltatnak a többi modulnak. Fontos elválasztani a feladatköröket, különben egy rohadt nagy káoszt kapsz a végén, amit képtelen leszel karbantartani, és a projekt emiatt fog összeomlani a végén, nem a pénzhiány miatt.

Mi van akkor, ha közben elfogy a pénz, és becsődöl az egész?

Nem értem ez hogyan kapcsolódik a témához. Ennyi erővel akkor nem is fektessünk energiát egy projektbe se, mert mi van, ha elfogy a pénz.
30

Nem tudom, hogy van e értelme

inf · 2014. Már. 28. (P), 20.59
Nem tudom, hogy van e értelme reagálni a továbbiakra, de azért megteszem.

Dolgozzunk OOP-ben! Hát ez így nem elégséges, be kell vezetni az OOP mintákat, mert anélkül nem lesz hatékony.

A design patterns az oo best practice-ek gyűjteménye. Egy olyan eszközkészlet, amit ha megtanul használni az ember, akkor könnyebbé teszi az oo fejlesztést.

Írjunk teszteket!

Az automatizált tesztekre szükség van, mert különben honnan tudnád, hogy eltörsz e valamit a programban, ha hozzányúlsz? Sehonnan.

De ez így nem elég, írjuk meg őket előbb, aztán csak magát a kódot

A fejlesztés menete a következő, először kérsz user story-t, az alapján use case-eket hozol létre, a use case-ek alapján teszteket írsz, a tesztek alapján pedig megírod a kódod. Ha nem írsz teszteket, akkor honnan tudod, hogy azt írod e meg, amit az ügyfél kért? Sehonnan, maximum a memóriádra támaszkodhatsz, ami általában kihagy. Persze lehet fejlesztgetni bele a vak világba, ha van időd...

Ha később a program változik, a teszteket is akár írhatom újra.

Ebből látszik, hogy nem szoktál teszteket írni, mert ha utólag írnád meg, akkor is ugyanígy írhatnád újra kód változtatásnál.

Nem mindegy, hogyan írom meg a teszteket, az egyes modulok közti összefüggéseket csökkenteni kell. Node a végső kódban a modulok egymással dolgoznak!

A laza csatolás fontos, az egyik legalapvetőbb dolog oo programozásban, és ugyanúgy érvényes kell, hogy legyen a modulokra is. Ha a modulok nem lazán csatoltak egymáshoz, akkor nem lesznek karbantarthatóak.

Valóban szükség van ilyen szintű bonyolításra?

Igen, valóban szükség van.