ugrás a tartalomhoz

Silex – menőségből jeles

Hidvégi Gábor · 2017. Már. 27. (H), 22.49
Az egyik fórumtémában találkoztam a Silex nevével, és gondoltam, utánaolvasok, mi is ez. Amit találtam, megdöbbentő volt.

Bemutatás

A honlapja szerint ez egy PHP mikro-keretrendszer, ami egy nagyon érdekes kijelentés. A githubról letöltve a forrása majdnem kétszáz kilobájt, ami azért nem mondható olyan kevésnek. De ez félrevezető, mert bizonyos részei a Symphony moduljaira épülnek, amit külön nem töltöttem le, de sejthető, hogy nem a tárhelyet fogja csökkenteni; a SecurityServiceProvider.php például a szülőjének ötven komponensére támaszkodik.

Mivel nem önálló termék, a telepítése kézzel nehézkes, a Composert ajánlják hozzá, ami egy újabb függőség.

Használat

Nézzük meg az első példát (kicsit kiegészítve):

$blogPosts = array(
  1 => array(
    'date'    => '2011-03-29',
    'author'  => 'igorw',
    'title'   => 'Using Silex',
    'body'    => '...',
  ),
);

$app->get('/blog/{id}', function () use ($blogPosts) {
  if (!isset($blogPosts[$id])) {
    $app->abort(404, "Post $id does not exist.");
  }
  $output = '';
  foreach ($blogPosts as $post) {
    $output .= $post['title'];
    $output .= '<br />';
  }

  return $output;
});

Ha valaki menőségi faktor alapján választ magának keretrendszert, nem szabad tovább keresni, a Silex maximális pontszámot ér el. A javascript világából ismerős lehet a callback-ek használata, és mindjárt az is eszünkbe juthat, hogy ezektől évekig próbáltak megszabadulni (callback hell), még szabványt is módosítani kellett emiatt, node idiótaságért a nodejs közösségnek sem kell a szomszédba mennie. A node.js esetében azért van szükség callback-ekre, mert az I/O műveletek aszinkron módon történnek; viszont a PHP-ban sorosan lehet programozni, emiatt ez a választás például az olvashatóságot csökkenti, de előnnyel nem jár.

A fenti kódból azonnal látszik, hogy például a külső változókat a névtelen függvényünkbe nem egyszerű paraméterként, hanem a use kulcsszó segítségével tudjuk injektálni. A keretrendszer felépítése miatt a belső függvény paraméterlistája fix, emiatt van szükség erre a megoldásra. Ez megköti a kezünket, a minimális php verziót, és igazából semmilyen előnye nincs a hagyományos függvényhíváshoz képest, ahol szabadon adhatjuk meg a paramétereket és sorrendjüket.

Az is feltűnhet, hogy sablonozás nincs, ha például HTML vagy XML kimenetet gyártunk, azt nekünk kell megoldanunk.

A Silexben sok olyan konvenció van, ami teljesen unintuitív, és szembemegy a hagyományokkal, ilyen például a $app->get(). Alkalmazások fejlesztésénél megszokott, hogy ha egy függvény vagy metódus neve ige, az valamilyen cselekvést jelképez (például a clean_input_variables() megtisztítja a bejövő változókat), ha "on"-nal kezdődik, akkor pedig egy eseménykezelőt takar (például az onclick() egy kattintást fog lekezelni). Ezzel szemben a Silexben a $app->get() a várakozásokkal ellentétben nem fog megszerezni semmit, hanem egy HTTP GET kérést fog feldolgozni. Ugyanígy a $app->post() nem adatokat fog küldeni az alkalmazásunk számára, hanem a HTTP POST kérést dolgozza fel. A $app->error() nem hibát fog generálni, hanem hibakezelőt regisztrál.

Ez hasonló, mint jQuery-ben a click() metódus, amitől azt várná az ember, hogy egy elemen egy kattintást fog szimulálni (mint a natív click() metódus), de nem, mert igazából ez egy eseménykezelő hozzárendelését végzi el. Nem tudom, hogy a Silexben is ezt az illogikus nevezéktant vették-e át, vagy csak rövidíteni akartak, mindenesetre zavaró. A $app->abort() már az alkalmazásra vonatkozik, nem a kérésre.

A keretrendszer lehetőséget ad egyéb HTTP metódusok (PUT, PATCH) használatára. Mindez szép, jó és "szemantikus" (ami menő), csak épp teljesen felesleges, és más szerepe nincs, csak a programot bonyolítja, hibaforrás.

$app->get('/blog/{id}', function ($id) {
  // ...
})
->when("request.headers.get('User-Agent') matches '/firefox/i'");

Lehetőség van a kontrollereink bizonyos szűrésére, mint a fenti példában láthatjuk. Itt is előjön a keretrendszer architektúrájának hátránya: a szűrőfeltételek a kontroller után vannak, ami teljesen ellentmond a józan észnek. Ha az ember elkezdi olvasni a kódot, előbb van az, hogy mit csinálunk, mint az, hogy mikor. Sehol máshol nincs ilyen, ez teljesen unintuitív, nem véletlenül nem terjedtek el annyira a hátultesztelő ciklusok. Ráadásul elvesztjük az else lehetőségét, azaz bizonyos esetekben bonyolult feltételeket vagyunk kénytelenek írni. Arról nem is beszélve, hogy a példa működéséhez újabb Symphony modult kell betölteni, pedig két függvényhívással elérhetnénk ugyanezt.

De – és ez az, ami a legmenőbb – lehet a metódusokat chainingelni. Ettől a programozó egy mahagóni borítású szobában érezheti magát, az egyik kezében egy szivarral, a másik kezében egy pohár kétszáz éves whiskey-vel, s közben épp egy lenge öltözetű karibi szépség próbálja megcsókolni, a nyelve hegyén egy kis kék kapszulát egyensúlyozva.

Mire jó?

A Silex dokumentációja a legtöbbet a kontrollereknek és a routingnak szenteli, pedig igazából ez nem egy túlzottan érdekes feladat, a bejövő GET és POST paraméterek alapján pár alap if és függvényhívás segítségével meg lehet oldani.

$darabok = explode('/', $url);
if ($darabok[0] === 'blog') {
  $bejegyzesek = (...) ;
  $bejegyzes = filter_var($darabok[1], FILTER_SANITIZE_NUMBER_INT);
  if (!isset($bejegyzesek[$bejegyzes])) {
    (...)
  }
}

Egy keretrendszerhez kötni magunkat mindenképp kiszolgáltatottság, mert nem rajtunk múlik, változik-e az API-ja (fő verzióváltáskor általában szokott mindenhol), mikor javítanak ki hibákat, mikor tesznek bele újakat, mikor fejezik be a fejlesztést. Főleg akkor nem túl ésszerű, ha a keretrendszer feladatait pár alap PHP függvénnyel mi is el tudjuk látni, ráadásul gyorsabban és hatékonyabban, kötöttségek nélkül. Nem beszélve a rejtett Symphony függőségről, ami merevvé és törékennyé tesz mindent, ami ráépül.

Az unintuitív elnevezések, hátultesztelő feltételek és felesleges funkcionalitás ha másra nem is jó, de kiváló "hogyan ne csináljunk valamit" példává teszi a Silexet.
 
1

Min lepodtel meg?

janoszen · 2017. Már. 28. (K), 02.43
Min lepodtel meg? Ket nagy Framework csalad van PHP teren, a Zend es a Symfony. Mindketto hatalmas bloatware, es a ra epulo cuccok is azok. Ha meg csak a core installt teszed fel, akkor hasznalhatatlan a cucc, mert se DB layerrel nem jon, se semmi massal.

Kb egy eve elkezdtem jatszani a Piccolo nevu csodaval, ami 100% modularis es a ket nagytol fuggetlen framework akart lenni, de idokozben elmult az eletembol a PHP, szoval annyiban maradt.
2

Mindenen

Hidvégi Gábor · 2017. Már. 28. (K), 08.53
Az rendben van, hogy a "nagyok" "túlterheltek", de már egy ilyen "mikro" keretrendszer dokumentációjának az olvasgatásakor többször is majdnem leestem a székről, akkora blődségeket láttam benne.

Ez az egész témakör ezer kérdést felvet, kezdve azzal, hogy hová tűnt a racionalitás? Miért kell minden hülyeséget belepakolni ilyenekbe? Biztos, hogy mindenre szükség van? Miért kell túlbonyolítani, amikor natív megoldásokkal minden szempontból jobb lesz a kód?

Egy "DB layer" az pár kilobájtos cucc, egy "router" is, onnantól kezdve elég pár szabályt betartani, és máris egy függőséggel kevesebb.
3

Írj sajátot

Pepita · 2017. Már. 28. (K), 09.22
Azért egy fw-nek az a szerepe, hogy a gyakran előforduló funkcionalitást tudja, és ne kelljen projektenként 0-ról lefejleszteni - még ma is racionális gondolat.

Miért kell minden hülyeséget belepakolni ilyenekbe?
Mert neked ugyan hülyeség, de a Jóska Pistának hátha pont erre lesz szüksége, és én, a készítő elmondhatom magamról, hogy már ilyet is csináltam.

Biztos, hogy mindenre szükség van?
Nem. Ha a nagyobb részére neked nincs szükséged, akkor ne használd.

Miért kell túlbonyolítani, amikor natív megoldásokkal minden szempontból jobb lesz a kód?
Ezt azért gondolom sokan vitatják, de nem mennék bele OOP - anti OOP vitába. Mindenkinek más és más fontos, hogy a keretrendszer tudja vagy magának szeretné fejleszteni.

Fentiek fényében azt gondolom, hogy neked is inkább saját framework-re lenne szükséged, miért ne fejlesztenél sajátot?
5

Azért egy fw-nek az a

Hidvégi Gábor · 2017. Már. 28. (K), 10.04
Azért egy fw-nek az a szerepe, hogy a gyakran előforduló funkcionalitást tudja, és ne kelljen projektenként 0-ról lefejleszteni - még ma is racionális gondolat.
Ostobaság lenne valamit mindig a nulláról lefejleszteni, én ilyet sehol sem állítottam. Azt viszont igen, hogy a Silex API-ja által nyújtott szolgáltatásokat az ember kiválthatja pár vérprimitív saját függvénnyel, amit aztán projektről projektre másolhat.

én, a készítő elmondhatom magamról, hogy már ilyet is csináltam
Ha a keretrendszerek arra valók, hogy a lányok előtt villogjunk vele, mert még ezt is beleraktam meg azt is, akkor jogosan merülhet fel a kérdés, hogy miért csak ennyi featúrával rendelkezik? Miért ne pakoljuk bele még ezt és azt, hogy hosszabb legyen az a bizonyos méregetnivaló?

Ezt azért gondolom sokan vitatják, de nem mennék bele OOP - anti OOP vitába
Semmiféle OOP-ről nincs szó, a natív dolgokra hoztam példát az írás végén.
31

Nagyon jó :)

Pepita · 2017. Már. 30. (Cs), 08.31
Miért ne pakoljuk bele még ezt és azt, hogy hosszabb legyen az a bizonyos méregetnivaló?
Hát hajrá, szállj be a fejlesztői csapatba, biztos van pár ötleted neked is, és hosszabb lesz! :-D
4

Javasolnám, hogy egy kicsit

smokey · 2017. Már. 28. (K), 09.25
Javasolnám, hogy egy kicsit mélyebben nézz utána, mielőtt véleményt alkotsz (kicsit erőse, és kioktatósan hangzik de nem annak szántam ;)).

Gyakorlatilag a cikk összes gondolatára van ellenérvem. Sajnálom, hogy csak a Silex dokumentációig jutottál és azt sem sikerült teljesen átvenned/átadnod. Említenék még pár Silex adta lehetőséget, amiről talán érdemes volna beszélni mélyebben:
- Dependency Injection
- Middleware
- Hiba kezelés
- Validáció
- Milyen függőségeket érdemes használni ahhoz, hogy intuitivabb módon tudd használni a rendszert >azért nem mindig rosszak a függőségek sem
- Nem csak callbackk-ekkel tudsz operálni
- Meg egyáltalán, hogy mire érdemes használni a keretrendszert

Hogy az utolsó pontra választ adjak:
Nem minden keretrendszer jó mindenre. A Silex-et szerintem HTML oldalakhoz nem érdemes használni, működik a TWIG Silexben is egyébként, meg natívan is lehet HTML-t generálni. Inkább REST API-k készítésére használnám, amire viszont kiváló és szerintem gyors. Egy adatbázis műveleteket végrehajtó kérést opcachel simán 70 ms körül lehet tartani (tárhelyszolgáltatónál!!!), ami szerintem azért nem rossz (nyilván lehetne jobb, és lehet is, ha megfelelő környezetben fut).

És egy általánosabb gondolat:
- Érdemes keretrendszert használni?
- Szerintem igen.
- És miért?
- Minek fejlesszem le újra, amit valaki már megcsinált, nem mellesleg van hozzá dokumentáció és mögötte kommuniti. És felteszem a kérdést: jobban meg tudom csinálni a sajátomat, mint azok a valakik? És ha igen, akkor azt újra fogom használni egy másik projecten is? Ha igen, akkor egy újabb függőséggel állunk szembe, ami a sajátunk... Ha nem, akkor meg drága lesz a fejlesztés hibázási lehetőséggel, nagy eséllyel dokumentáció nélkül.
- Érdemes függőségeket használni?
- Szerintem igen.
- És miért?
- A fent leírtak miatt; tartom a véleményem.

A microframeworkok (és a Symfony is) - ahogy én azt korábban levettem - önmagában arra jók, hogy lekezeljék a kérést és adjanak lehetőséget válasz adásra, és ezt támogassa meg egyfajta alap működéssel, ami ha kell cserélhető és kiterjeszthető, adott esetben meg jó, ahogy van.

Még egy dolog: ha a project mérete a függőségek miatt nagy, akkor kell csinálni egy build scriptet, ami kivágja azokat a fájlokat, amikre biztosan nem lesz szükséged runtime (unit tesztek, readme fájlok, batch fájlok, licens fájlok, stb), és a 10mb-os projectből csináltál egy 1mb-osat.
6

Mélyebben

Hidvégi Gábor · 2017. Már. 28. (K), 10.35
Az általad felsoroltakat (Dependency Injection és társaik) azért nem fejtettem ki, mert nem akartam túl hosszúra nyújtani. Szerintem is megérik, hogy menjünk bele mélyebben, meg is fogom tenni.

Gyakorlatilag a cikk összes gondolatára van ellenérvem
Szeretném látni!

azért nem mindig rosszak a függőségek sem
Ez megér egy kifejtést

Függőségek
Már a szóban benne van minden: képzeld magad egy láncra kötött élőlénynek. A függőség keretet ad és korlátoz, mert csak egy bizonyos szintig enged elmenni. Minél több a függőség, annál kevésbe tudsz mozogni, és egyre nagyobb a veszélye, hogy megfojtod magad.

Ha embernek születtél, minden függőség rabszolgává tesz. Ha viszont ezeket a kereteket te állítod fel magadnak, akkor minden úgy fog történni, ahogy kell.

Ha kutyának születtél, akkor talán jó is, hogy vannak ilyenek, mert a kutya ösztönlény, némileg tanítható, de benne van, hogy harapsz, ezért kell a lánc. És ha kutyának születtél, ne vitatkozz emberekkel!

Mindez lefordítva azt jelenti, hogy a függőség kiszolgáltatottá tesz azoktól, akik készítik. Ezért célszerű azt a társaságot vizsgálni, akik az adott szoftvert írták. Egy PHP belátható ideig működni fog és elérhető lesz, de egy node.js esetében ez már nem mondható el, mert sosem tudhatod, megint mikor válik ketté a gyerekes attitűdökkel rendelkező fejlesztői közösség, mikor találnak ki újabb megoldást a callback hell-re stb. Instabil.

jobban meg tudom csinálni a sajátomat, mint azok a valakik? És ha igen, akkor azt újra fogom használni egy másik projecten is? Ha igen, akkor egy újabb függőséggel állunk szembe, ami a sajátunk...
Az ember az évek során felszed némi tudást. Ha nem tudod jobban megcsinálni, akkor ott valami gond van.

Ha a függőség a te kezedben van, az a legjobb, mert minden pontosan úgy fog történni, ahogy elképzelted.

jobban meg tudom csinálni a sajátomat, mint azok a valakik? És ha igen, akkor azt újra fogom használni egy másik projecten is? Ha igen, akkor egy újabb függőséggel állunk szembe, ami a sajátunk... Ha nem, akkor meg drága lesz a fejlesztés hibázási lehetőséggel, nagy eséllyel dokumentáció nélkül.
Semmi sem készül el véletlenül. Ha valamit csak egyszer kell megírni, és nem lehet továbbvinni, az valószínűleg ahhoz az egy projekthez kellett. Az utolsó mondatod érdekes: félsz attól, hogy hibázni fogsz? Nem dokumentálod a projekteket? Szerintem ezeken érdemes lenne elgondolkodnod.

A microframeworkok (és a Symfony is) - ahogy én azt korábban levettem - önmagában arra jók, hogy lekezeljék a kérést és adjanak lehetőséget válasz adásra, és ezt támogassa meg egyfajta alap működéssel
Az élet pont annyira egyszerű, ahogy leírod. Ha bejön egy kérés, gyakorlatilag egy feltételrendszer szerint be kell include-olni néhány fájlt Ha az első paraméter "blog", include(blog.php), ha "termékek", include (termekek.php), különben meg include(404.php) Minek ide keretrendszer?

Aztán a bejövő paramétereket tisztítani kell és eldönteni, mit csináljunk: if valid(paraméter), ment(adatok), különben hiba(). Minek kéne ezt túldimenzionálni?
7

Szeretném látni! Szeretem

smokey · 2017. Már. 28. (K), 11.50
Szeretném látni!


Szeretem volna gyorsan reagálni, idő hiányában nem fejtettem ki, ha lesz rá kapacitásom megteszem.

Az ember az évek során felszed némi tudást. Ha nem tudod jobban megcsinálni, akkor ott valami gond van.


Nem megfelelően fogalmaztam, jobb kérdés lenne talán az, hogy: az enyém tud-e többet annyival, hogy megérje lefejleszteni, van-e hozzáadott értéke egy már kész komponenshez képest.

Fűggőségek


A jó döntést meg kell tudni hozni. Tényleg van egy csomó olyan komponens, amit tök felesleges lefejleszteni, mert kész, ott van, használd, működik. Cél szentesíti az eszközt: ha nem válik be egy függőség sem az igényem kielégítéséhez, nyilván készítek egy sajátot. Ott a WordPress, meg egy rakat plugin. Eszembe nem jutna lefejleszteni egyet sem, mert mindenre van megoldás. Érdemes bele ölni a saját időmet ha más már bele ölte a sajátját, és nekem adta? Szerintem nem.

Az utolsó mondatod érdekes: félsz attól, hogy hibázni fogsz? Nem dokumentálod a projekteket? Szerintem ezeken érdemes lenne elgondolkodnod.


Nem félek. Miért félnék? Mindenki hibázik, lehet javítani. Dokumentálom a projectet, viszont itt nem teljesen tiszta, mire gondolsz.

Az élet pont annyira egyszerű, ahogy leírod. Ha bejön egy kérés, gyakorlatilag egy feltételrendszer szerint be kell include-olni néhány fájlt Ha az első paraméter "blog", include(blog.php), ha "termékek", include (termekek.php), különben meg include(404.php) Minek ide keretrendszer?

Aztán a bejövő paramétereket tisztítani kell és eldönteni, mit csináljunk: if valid(paraméter), ment(adatok), különben hiba(). Minek kéne ezt túldimenzionálni?


De ezeket miért oldjam meg én, mikor megoldja helyettem más? Ismét egy kérdés: szép lesz a kódod egy rakat iftől, ahogy egy idő után azt sem tudod mi van? Van 50 sornyi validációd, meg egy sornyi adatbázis műveleted. Miért írjam meg az 50 sor validációt ha ott van rá a megfelelő komponens, ami blackboxként működik - igen, nem is akarom tudni hogyan, az a lényeg, hogy oldja meg a problémámat. Használom a validátort, és 10 sorból megúsztam egy bárminek a validációját úgy, hogy látm is mi történik, nem csak debuggolom az ifeket.

Ha visszakanyarodunk a routingra, és egy REST API-ról beszélgetünk - ahol érdemes betartani bizonyos konvenciókat, akkor azért annyira nem triviális, hogy if/include. Illetve de, az, csak nem mindegy, hogy egy 2 paramétert lekezelő routra kell írnom egy regexet, amit fél órán keresztül debuggolok, hogy miért nem jó, + keletkezik néhány sor kód, ami megint átláthatatlanabbá teszi a saját kódomat, vagy használok egy jól működő routert, ami mögött van egy normális leírás, amit egyszer elég elolvasni, felfogni és használni.
8

az enyém tud-e többet

Hidvégi Gábor · 2017. Már. 28. (K), 12.37
az enyém tud-e többet annyival, hogy megérje lefejleszteni, van-e hozzáadott értéke egy már kész komponenshez képest
A tied azt, és csakis azt a műveletet fogja elvégezni, amire kéred. Egy keretrendszer általános megoldást ad, azaz mindenképp nehezebb és lassabb lesz. Tehát a válasz igen, van hozzáadott értéke.

Persze mindenki magából indul ki. Én például mindig magam fejlesztettem le mindent, így az évek során összejött egy kis eszközkészletem, függvénytáram, amit minden projektben használok, és van egy rálátásom, mi hogyan történik egy kliens-szerver kérés kapcsolatban.

Ha valaki világéletében keretrendszerek segítségével fejlesztett, valószínűleg fogalma nincs sok mindenről. De így miről lehet vitatkozni?

Ott a WordPress, meg egy rakat plugin. Eszembe nem jutna lefejleszteni egyet sem, mert mindenre van megoldás
Igen, egyszer én is dolgoztam WordPress-szel, de amikor a megrendelőnek olyan kérése volt, amire napokig nem találtunk megfelelő plugint, és a meglévőt sem lehetett egyszerűen átírni, leültem, és írtam egyet magamtól. Akkor meg már ugyanott vagyunk, ahol a part szakad.

viszont itt nem teljesen tiszta, mire gondolsz
A következőt írtad:
jobban meg tudom csinálni a sajátomat, mint azok a valakik? És ha igen, akkor azt újra fogom használni egy másik projecten is? Ha igen, akkor egy újabb függőséggel állunk szembe, ami a sajátunk... Ha nem, akkor meg drága lesz a fejlesztés hibázási lehetőséggel, nagy eséllyel dokumentáció nélkül.
Te írtad, hogy ha nem tudod újra felhasználni, akkor drága lesz a fejlesztés és dokumentáció sem lesz.

Ismét egy kérdés: szép lesz a kódod egy rakat iftől, ahogy egy idő után azt sem tudod mi van?
Nem tudsz spórolni, ott lesznek az if-ek, csak más formában. Ez:
$app->get('/blog', function () {
  (...)
}->when("request.headers.get('User-Agent') matches '/firefox/i'")

Ekvivalens ezzel:
if ($url[0] === 'blog' and strpos(strtolower(getallheaders()['User-Agent']), 'firefox') !== false) {
  (...)
}

Ráadásul a PHP-s példában egyben látod az egészet, míga a Silexben a feltétel két részre van törve.
Az utóbbihoz ráadásul elég a PHP alap függvényeit használni, amik egyszerűek és ugyanolyan jól dokumentáltak, mint bármi más, sőt.
10

A tied azt, és csakis azt a

smokey · 2017. Már. 28. (K), 13.09
A tied azt, és csakis azt a műveletet fogja elvégezni, amire kéred. Egy keretrendszer általános megoldást ad, azaz mindenképp nehezebb és lassabb lesz. Tehát a válasz igen, van hozzáadott értéke.


Egyetértek. DE, ha tudok időt spórolni, és az ügyfél ugyanannyit fizet érte, akkor nem fogom lefejleszteni.

Persze mindenki magából indul ki. Én például mindig magam fejlesztettem le mindent, így az évek során összejött egy kis eszközkészletem, függvénytáram, amit minden projektben használok, és van egy rálátásom, mi hogyan történik egy kliens-szerver kérés kapcsolatban.


Minden fejlesztőnek van ilyen tára, aki jó pár éve dolgozik, nekem is. Nem azt mondtam, hogy ne csinálj ilyet, mert van mikor ez kell. De ha egy olyanra van szükséged, ami készen van, akkor részemről nem kérdéses a dolog.

Ha valaki világéletében keretrendszerek segítségével fejlesztett, valószínűleg fogalma nincs sok mindenről. De így miről lehet vitatkozni?


Ezt most kicsit magamra vettem, bocs - lehet nem jogosan... Tapasztalt fejlesztőnek tartom magam, és én is láttam már egyet, s mást, többek között ügyfeleket is, aki pont nem foglakozik azzal, hogy Silex, Symfony, saját, vagy más. Neki az a lényeg, hogy működjön, és ha olcsóbban ki lehet hozni keretrendszerből, amit jól ismersz, akkor miért ne?

Nem tudok olyan fejlesztő ismerősömről, aki valaha nem próbálkozott volna sajáttal. Szerintem az a legjobb tanuló pénz ;). Nagy részük rájött, hogy lefejlesztették azt, ami ott van az orruk előtt. A másék rész pedig dacból nem használja, mert az övé jobb - vagy úgy gondolja, hogy jobb.

Te írtad, hogy ha nem tudod újra felhasználni, akkor drága lesz a fejlesztés és dokumentáció sem lesz.


Így már világos mire céloztál.
"nem tudom újra használni", értem ez alatt: túl speciális lett, hogy másnak is eladd
"drága lesz a fejlesztés": több munka magasabb költségeket generál
"nem lesz dokumentáció": aki azt mondja, hogy a saját maga által készített rendszert minden esetben olyan mélységik dokumentál, mintha azt egy közösségnek csinálná, akkor az szerintem hazudik.

Készüljön dokumentáció minden esetben, de csak annyi, amennyi kell, és amennyit elolvasnak!

Javítanék az egyik kódblokkodon, ha a teljességre törekszünk:

if (isset($url[0]) && $url[0] === 'blog' and function_exists('getallheaders') && isset(getallheaders()['User-Agent']) && strpos(strtolower(getallheaders()['User-Agent']), 'firefox') !== false) {
  (...)
}
míga a Silexben a feltétel két részre van törve


Igen, mert a két if más szerepet tölt be. Ennyi erővel a validációt, adatbázis szintű vizsgálatot meg még sok mást rakhatnék ide, egy darab if-be. (a getallheaders-t azért vizsgálom, mert volt már precedens korábban arra, hogy nem létezett ez a függvény, mert ha az emlékezetem nem csak, akkor ez egy apacheon futó PHP-s függvény, és nginx alatt lehet gáz > janoszen ezt talán pontosabban tudja)
9

Egyébként, lehet a téma

smokey · 2017. Már. 28. (K), 13.06
Egyébként, lehet a téma elnevezése nem sikerült, mert átmentünk egy "használj keretrendszert, vagy ne" vitába :D, ami a cím szerint OFF; viszont maradjunk itt szerintem, és folytassuk, másik szálon elhalna a beszélgetés...
12

Keretrendszer

Hidvégi Gábor · 2017. Már. 28. (K), 13.48
Ezt a szálat te indítottad el az első hozzászólásoddal. A téma bevezetőjében írt kritikám a Silexre vonatkozott, és nem általában a keretrendszerekre.
14

Igen

smokey · 2017. Már. 28. (K), 13.53
Igen
53

Nem tudom php-ban hogy van,

inf · 2017. Ápr. 12. (Sze), 19.10
Nem tudom php-ban hogy van, de node-nál ez a fejlesztő dolga, hogy betegye npm ingnore-ba a teszteket, readme-t, stb. és csak a kód maradjon a modul berántásánál. Gondolom composer is azért nyújt erre lehetőséget...

Én személy szerint nem azért használok függőségeket, mert ne tudnám jobban megírni. Ezek inkább arra valóak, hogy időt spórolj, és a projekttel foglalkozz a körítés helyett. A rosszul dokumentált függőségek néha még rosszabbak, mintha nulláról írnál egy keretrendszert a témára.
11

Ezzel a témával kb 10 évvel

Práger Ádám · 2017. Már. 28. (K), 13.41
Ezzel a témával kb 10 évvel visszatekerted az időt. Szerintem legközelebb kezdjünk el azon vitatkozni, hogy a unit tesztelés jó-e, vagy nem. Vagy hogy a javascriptnél kell-e semicolon a sor végére.

Frameworköt teszteltél... ott általában akadnak előre letett dolgok :)

Pár dologhoz azért lenne hozzáfűzni valóm.

Bloated: És akkor mi van? Hála az istennek, hogy bloated. Francnak van kedve 10 év webezés után DB layereket, meg routereket írkálni. Ezek a komponensek pedig agyon tesztelt, optimalizált kóddal jönnek, megbízható, open soure forrásból. Akár tetszik akár nem, amit te írsz csak rosszabb lehet, még akkor is ha jó programozó vagy. Gondolom nincs mögötted 7 millió dollár (symfonyba fektetett pénz) hogy frameworköt írj. Ezeknek a dolgoknak a performance impactja pedig minimális.

Dependency rossz?: Nem. A rossz dependency rossz. Ha van egy lib amire felépítetted a projektedet, de több baj van vele mint amit használ az rossz. Ezért kell jól átgondolni, mielőtt használsz egyet. Normális esetekben nagyon is jó a dependency.

Request-response framework: Ha mindenáron csak egy tök alap return $response dologra vágysz, akkor szerintem nézz rá a Go framekre, ott elég nagy divat ez. (Bár pár dolgot azok is hoznak magukkal)
13

Köszönöm! +1

smokey · 2017. Már. 28. (K), 13.52
Köszönöm! +1
15

Ezzel a témával kb 10 évvel

Hidvégi Gábor · 2017. Már. 28. (K), 13.54
Ezzel a témával kb 10 évvel visszatekerted az időt
Lásd 12-es hozzászólás

Frameworköt teszteltél... ott általában akadnak előre letett dolgok :)
Nyilván, csak nem mindegy, hogy azok a letett dolgok úgy működnek, ahogy az ember elvárja, vagy valami kifordított logikával, ahogy a Silexben.

Bloated: És akkor mi van? Hála az istennek, hogy bloated. Francnak van kedve 10 év webezés után DB layereket, meg routereket írkálni.
A Silexben nincs adatbáziskezelés. Ha meg ennyi idő alatt nem hozott valaki össze egy routert, rég rossz.
16

Ha meg ennyi idő alatt nem

Práger Ádám · 2017. Már. 28. (K), 14.07
Ha meg ennyi idő alatt nem hozott valaki össze egy routert, rég rossz.


Írtam én kb mindent, a routertől a teljes frameworkig. Rengeteget lehet belőle tanulni, többek között azt is, hogy többet nem fogok írni, mert nem tudok jobbat mint ami fentvan githubon és több 100 ember munkája van benne.

A Silexben nincs adatbáziskezelés

Ez a legjobb példa egy kitűnő dependencyre: opcionális, de támogatott. A symfony/silex egy decoupled componens halmaz, az alapból kapott "frameworkök" csak előre definiált részhalmazok, amiből kiválaszthatod a projektednek megfelelőt.

Symfony > Symfony microkernel > Silex

Ezen kívül vannak még jobban specializált dolgok, mint pl a Symfony Rest edition, a most készülő Symfony Flex, vagy a zseniális API platform.
17

Hat azert

janoszen · 2017. Már. 28. (K), 14.50
Hat azert azt meg kell mondjam, hogy mindket oldalon van itt igazsag. Hiaba tettek a Symfonyba 7 misit, attol meg ugyanugy elofordul vele hogy xdebuggal kell nezegessem hogy mi a baja egy random dependency update utan. Feher oldal, hibauzenet nulla. Tenk ju.

A Silex elso ranezesre nekem szimpatikus volt, bar en szeretem az OOP-sabb, osztalyra routolt requestes semakat.

A DB hianya inkabb oda vezet vissza, hogy a Doctrine kb. az egyetlen mainstream DB layer, jo lenne ha lenne legalabb egy nagyobb konkurens.
18

Ez igaz, hiba mindenhol van.

Práger Ádám · 2017. Már. 28. (K), 15.11
Ez igaz, hiba mindenhol van. Symfonyban is volt egy rakattal, főleg a 2.0 és 2.3 releasek után. Csak inkább segítek githubon javítani, minthogy sajátot akarjak... abban is lesz hiba.
20

Jellemzoen

janoszen · 2017. Már. 28. (K), 15.39
Jellemzoen a problema nem akkor van amikor GitHubig eljut az issue, hanem sokkal elobb, amikor azt sem tudod mi tortenik es meg sem tudod mutatni senkinek bizonyos titoktartasi kotelezettsegek miatt.
19

Ezek a komponensek pedig

Hidvégi Gábor · 2017. Már. 28. (K), 15.36
Ezek a komponensek pedig agyon tesztelt, optimalizált kóddal jönnek, megbízható, open soure forrásból. Akár tetszik akár nem, amit te írsz csak rosszabb lehet, még akkor is ha jó programozó vagy.
Ez hülyeség. Az én kódom semmi mást nem csinál, csak amit beleírok, míg egy általános keretrendszer ezer ember igényeinek kell megfeleljen. Minél több komponensből áll, annál több a hibázás lehetősége, mert annál nehezebb lesz átlátni, melyik programszál mikor és milyen paraméterekkel fut le.

Lehet, hogy az egyes elemek overhead-je minimális, de ez összeadódik, mert rákényszerülsz – pont az általánosság miatt – többnek a használatára.

A heartbleed óta pedig tudjuk, hogy mennyire lehet komolyan venni a nyílt forrást meg a many eyeballs-t.

De ha már választani kell, akkor inkább egy kisebb keretrendszert (Silex), mint egy nagyot (Symphony).
21

Amikor már elfelejteném,

bamegakapa · 2017. Már. 28. (K), 21.11
Amikor már elfelejteném, miért csak az ördögszekereket fújja itt a szél, jön egy ilyen írás, és eszembe ötlik. És elszomorodom. Bocsánat, meg kellett osztanom, mehet tovább...
22

+1

T.G · 2017. Már. 28. (K), 21.27
+1
54

+1

inf · 2017. Ápr. 12. (Sze), 19.14
+1
23

HG, ennek a cikknek mi volt a

BlaZe · 2017. Már. 28. (K), 23.53
HG, ennek a cikknek mi volt a célja? :) Nem ismerem a fw-t, de azt nem gondolhatod komolyan, hogy az egymás után behányt if halom jobb, meg intuitívabb, mint amit a framework nyújt. Pl tesztet írni nem a magabiztosság hiányának a jele :)

Valamint egy frameworkkel szemben a PHP backward compatibility-jét felhozni érvként szerintem eléggé öngól. Hirtelen semmi mást nem tudok mondani, ami magasabbról tesz rá, mint a PHP. Ha ezt a nyelv okozta bizonytalanságot esetleg egy framework el tudja fedni a fejlesztők elől, akkor talán megéri megtanulni.
24

Mondjuk ez csak egy fórum

sly · 2017. Már. 29. (Sze), 11.31
Mondjuk ez csak egy fórum téma, szerintem HG sem cikknek szánta. :D
25

Cél

Hidvégi Gábor · 2017. Már. 29. (Sze), 12.09
Az a cél, hogy tessék elkezdeni gondolkodni.

Vegyük a routingot:
$app->get('/blog', function ($id) {
  // ...
})
->when("request.headers.get('User-Agent') matches '/firefox/i'");

Miért nem intuitív? Mert ránézel a kódra, és elsőre nem egyértelmű, hogy mikor fog lefutni.

A keretrendszer készítői kiemelték az url első részletét, ami a fenti példában a "/blog"-nak felel meg, és erre építették fel a koncepciót. Miért? Mint látható, ez nem elég, mert van egy olyan további feltétel is, hogy ráadásul a böngészőnek firefoxnak kell lennie. Tehát az url == "blog" és böngésző == "firefox"-nak egyszerre kell teljesülnie, egyenértékűek. Akkor miért vették külön?

Ráadásul elképzelhető az, hogy egy feltétel több kombinációban szerepelhet, például:
if ($url == 'blog') {
  if (böngésző == 'firefox')
    route 'blog_firefox';
  else
    route 'blog';
}

Ezzel szemben Silexben már csoportosítani kell:
$blog = $app['controllers_factory'];
$blog->get('/', function () {
  return 'Blog home page';
});
$blog->get('/', function () {
  return 'Firefox';
})->when('User-agent = firefox');
$app->mount('/blog', $blog);

Melyik az egyszerűbb és átláthatóbb (és mellékesen gyorsabb)? Amíg te azzal szerencsétlenkedsz, hogy megtanuld, a különböző esetekben a framework melyik "szintaxisát" kell használni, én még mindig csak a natív if-eket pakolgatom nulla befektetéssel.

A fentiek fényében nem értem a kérdésed.

Valamint egy frameworkkel szemben a PHP backward compatibility-jét felhozni érvként szerintem eléggé öngól.
Visszaolvastam, amit eddig írtam, és sehol sem érveltem a PHP backward kompatibilitásával. Tudnál idézni?
26

$app->get('/blog', function

smokey · 2017. Már. 29. (Sze), 15.09

$app->get('/blog', function ($id) {
  // ...
})
->when("request.headers.get('User-Agent') matches '/firefox/i'");


Kismillió dolgtól függhet még, hogy egyáltalán lefusson a függvény. Nem csak attól, hogy '/blog', Firefox. Lehet, hogy menet közben megakasztja egy másik middleware. Ami fenti kód blokkban van, az két if, de mire ideér a program, addig lefut még sok if, amit egyben szerintem nem szeretnél látni soha. Lehet, hogy szét van tördelve, viszont mindennek megvan a helye. Van authentikációs szűrő, authorizációs szűrő, ilyen szűrő, olyan szűrő... azt tudod, hogy egy végpontra milyen szűrők vonatkoznak, tehát tudod hol keresd a bajt, ha van.

Miért nem intuitív? Mert ránézel a kódra, és elsőre nem egyértelmű, hogy mikor fog lefutni.



Előbb kiderítem, mi történik itt, mint egy includokkal teli if halmazba.

Melyik az egyszerűbb és átláthatóbb (és mellékesen gyorsabb)? Amíg te azzal szerencsétlenkedsz, hogy megtanuld, a különböző esetekben a framework melyik "szintaxisát" kell használni, én még mindig csak a natív if-eket pakolgatom nulla befektetéssel.


Van honnan megtanulni, tehát nincs probléma, nem veszem el más idejét. A saját kódodat ki magyarázza el nekem úgy, hogy megértsem és ne vegyem el az idődet?
27

Van authentikációs szűrő,

Hidvégi Gábor · 2017. Már. 29. (Sze), 16.50
Van authentikációs szűrő, authorizációs szűrő, ilyen szűrő, olyan szűrő...
Mi a különbség az authorizáció és az authentikáció között?

Egyébként továbbra is a routernél vagyunk, ami útválasztó. Nálunk legalábbis egy van belőle, és a klienstől kapott adatok alapján eldönti, hogy merre menjen tovább a feldolgozás. Szerintem sokkal egyszerűbb, hogy ha tudom, hogy routing probléma van, egy helyen kell keresnem, nem szétszórva ezer fájlban.

Ez azzal az előnnyel jár, hogy nulla betanulási ideje van, míg a Silex esetében utána kell járnia a programozónak, hogyan működik, fejben kell tartania azokat a helyeket, ahol routing történhet.

Előbb kiderítem, mi történik itt, mint egy includokkal teli if halmazba.
Nem muszáj include-okat használni, ez részletkérdés. Biztos te is ismersz más módszereket, ugye?

A saját kódodat ki magyarázza el nekem úgy, hogy megértsem és ne vegyem el az idődet?
Én például el szoktam olvasni a kódot, hogy megértsem, hogyan működik. Ha van dokumentáció, bónusz! Ebből még nem volt probléma.
28

Auth

janoszen · 2017. Már. 29. (Sze), 17.08
Mi a különbség az authorizáció és az authentikáció között?


Autentikacio = be tudsz lepni (van valid usered es jelszavad)
Autorizacio = van jogosultsagod egy adott eroforrasra.

Egyebkent ezek egyikenek sincs helye a routingban, ennek illik az uzleti logikaban laknia.
29

Mi a különbség az

smokey · 2017. Már. 29. (Sze), 21.23
Mi a különbség az authorizáció és az authentikáció között?


Ezt már megválaszolták, azt hittem ez egyértelmű, bocsi.

Ez azzal az előnnyel jár, hogy nulla betanulási ideje van, míg a Silex esetében utána kell járnia a programozónak, hogyan működik, fejben kell tartania azokat a helyeket, ahol routing történhet.


Nézzük a következő esetet:
- Adott egy termék, és egy adminisztrátori funkció: hozzászeretnék rendelni három kategóriát egy termékhez, a kategóriákat a megfelelő felületen egy checkbox lista segítségével jelöltem be (a listában 3 kategória volt bejelölve). Egy ilyen jellegű funkció többé kevésbbé van minden admin felületen. A rendszerben van anonymus és vásárló felhasználó is. Mit kell vizsgálnod?
- A route-ot
- Adatbázis kapcsolatot
- Be van-e lépve
- Van e joga terméket módosítani (admin-e)
- Létezik-e a módosítandó termék
- Léteznek-e a kategóriák, amit hozzá akar rendelni a termékhez
- Hozzá vannak-e már rendelve a kategóriák a termékhez

Ha minden stimmel, mehet az action.

Az eddigiek alapján ezt naggyából egy, max 2 if-fel oldanád meg. Jól értem? Ha igen, mutatnál egy példa kódot - akár pseudot?

Nem muszáj include-okat használni, ez részletkérdés. Biztos te is ismersz más módszereket, ugye?


Igen ismerem a require-t, sőt a require_once-t is :D. Viccet félre téve, igen, szívesen használók namespaceket is, kiváló eszköz arra, hogy autoloadolni lehessen MINDENT. Ráadásul segít átláthatóvá tenni, és megfelelően rétegeltté tenni az alkalmazást, meglepő mód a Silex alkalmazásaim is így vannak felépítve. Külön validációs-, authentikációs, authorizációs, controller-, service-, adatbázis- (entity+repository+pdo) rétegek mindenféle objektum tarnszformálós megoldással, meg egyéb utilokkal. Hogy miért ennyi osztály, mikor van ami működik tömbbel is (pl adatbázis kezelés)? Én az az asszociatív tömb kerülős fajta vagyok.

Én például el szoktam olvasni a kódot, hogy megértsem, hogyan működik. Ha van dokumentáció, bónusz! Ebből még nem volt probléma.


Nah, legalább egy valami, amiben egyet értünk, sajnos nem mindenki így áll neki ;)
45

Az eddigiek alapján ezt

Hidvégi Gábor · 2017. Ápr. 9. (V), 15.39
Az eddigiek alapján ezt naggyából egy, max 2 if-fel oldanád meg. Jól értem? Ha igen, mutatnál egy példa kódot - akár pseudot?
Annyi if-fel oldanám meg, ahány szükséges:

if (!adatbazis_kapcsolat()) {
  return array('hibakod' => 500);
}
if (!belepve()) {
  return array('hibakod' => 401, 'url' => 'bejelentkezes');
}
if (jogosultsag_bitmaszk('termek_modositas') & felhasznalo_kulcs() == 0) {
  return array('hibakod' => 403);
}
if (!($termek_adatok = termek_adatok($_POST['termek']))) {
  return array('hibakod' => 404);
}
foreach ($_POST['kategoriak'] as $kategoria) {
  if (!($kategoria_adatok = kategoria_adatok($kategoria))) {
    return array('hibakod' => 400);
  }
  if (in_array($kategoria, $termek_adatok['kategoriak'])) {
    return array('hibakod' => 500);
  }
}

A visszatérési tömbbe nyilvánvalóan bele lehet tenni a pontos hibakódot/hibaüzenetet.

szívesen használók namespaceket is, kiváló eszköz arra, hogy autoloadolni lehessen MINDENT
Ezt nem igazán értem, névterek nélkül is működik az automata betöltés.

Már csak azért sem értem, mert ha úgyis be kell tölteni mindent, akkor minek használod az autoloadert? Nem egyszerűbb beletenni a fájlneveket egy tömbbe, végigiterálni és beinclude-olni őket?
60

Annyi if-fel oldanám meg,

smokey · 2017. Ápr. 13. (Cs), 14.34
Annyi if-fel oldanám meg, ahány szükséges


És ezt az összes actionbe beteszed, holott az első kettő mondjuk 100 másik action feltétele?

Már csak azért sem értem, mert ha úgyis be kell tölteni mindent, akkor minek használod az autoloadert?


:D ... bocs.. erre nem tudok mást mondani. Egyébként nem kell betölteni mindent. Ha van 1000 osztályom/fájlom, de egy kérés alkalmával csak 14-et használok, akkor az a 14 lesz betöltve.

Nem egyszerűbb beletenni a fájlneveket egy tömbbe, végigiterálni és beinclude-olni őket?


Nem. Ott az autoloader, megoldja, akkor megint minek dolgozzak vele feleslegesen?
30

Én százszor inkább dolgoznék

BlaZe · 2017. Már. 29. (Sze), 23.33
Én százszor inkább dolgoznék olyan projecten, ahol így, vagy hasonlóan van definiálva a routing, mint az általad jó példaként hozott if pakolgatással. Hoztak fentebb pár érvet, hogy miért.

Ez egy példa saját projectről jó régről, mutat némi hasonlóságot. Azóta ebbe is alaposan bele tudnék kötni, de speciel nem azért, mert az if jobb lenne, vagy mert bármilyen szempontból is hatékonyabb. Annál ez is sokkal jobb. Nem tudom látod-e mire gondolok. Szerintem akik a Silexet favorizálnák jobban ebben a threadben, elég hamar meglátják mi itt a baj :)
$dispatcher->mountCommand( '/megrendeles/adatok/', 'OrderDataCommand' );
$dispatcher->mountCommand( '/megrendeles/veglegesites/', 'OrderFinalizeCommand' );
$dispatcher->mountCommand( '/megrendeles-visszaigazolas/', 'OrderCommand', 'confirm', array( 'checksum', 'order_id' ), 'hu' );
$dispatcher->mountCommand( '/megrendeles-visszavonas', 'OrderCommand', 'cancel', array( 'checksum', 'order_id' ), 'hu' );
$dispatcher->mountCommand( '/order/data/', 'OrderDataCommand' );
$dispatcher->mountCommand( '/order/finalize/', 'OrderFinalizeCommand' );
$dispatcher->mountCommand( '/order-confirm/', 'OrderCommand', 'confirm', array( 'checksum', 'order_id' ), 'en' );
$dispatcher->mountCommand( '/order-cancel', 'OrderCommand', 'cancel', array( 'checksum', 'order_id' ), 'en' );
Visszaolvastam, amit eddig írtam, és sehol sem érveltem a PHP backward kompatibilitásával. Tudnál idézni?
Íme:

Egy keretrendszerhez kötni magunkat mindenképp kiszolgáltatottság, mert nem rajtunk múlik, változik-e az API-ja (fő verzióváltáskor általában szokott mindenhol), mikor javítanak ki hibákat, mikor tesznek bele újakat, mikor fejezik be a fejlesztést. Főleg akkor nem túl ésszerű, ha a keretrendszer feladatait pár alap PHP függvénnyel mi is el tudjuk látni, ráadásul gyorsabban és hatékonyabban, kötöttségek nélkül.
Ezzel szemben én azt állítom, hogy a PHP backward incompatibility-je akkora risk, hogy önmagában ezért érdemes elrejteni egy mainstream framework mögé, amit karbantartanak, és a közösség patch-eli a PHP verziókhoz.

Ami a (végrehajtási) sebességet illeti, azt akkor érdemes döntési szempontként felhasználni, ha olyan kimérT lassulást okoz, ami nem elfogadható. Egyébként a fejlesztő ideje sokkal drágább, mint a vas. És ahol ilyen szinten felmerül a mikrooptimalizáció, ott már az architektúra rég támogatja a skálázást. Ha nem, architektet kell cserélni, nem metódushívást.

Ebben az általad hozott esetben ráadásul arról se vagyok meggyőződve, hogy a sok if feltétlenül gyorsabb. Tekintsünk pl 5000 commandot. Az neked átlagosan 2500, worst case 5000 if. Nekem meg egy hashtable. Nincs kedvem lemérni, de szerintem én nyertem :) Nem tudom hol fordul, de valószínűleg már hamarabb.
32

Egyszerűségre kell törekedni

Hidvégi Gábor · 2017. Már. 30. (Cs), 08.48
A beillesztett kódod pont ugyanannyira unintuitív, mint a Silex, ránéz az ember, és törheti a fejét, hogy melyik paraméter mit jelent. Tele van redundanciával, és nem is csodálom, ha ma már inkább letagadnád. Ráadásul a legszebb, hogy a háttérben ugyanúgy if-ek vannak.

Főleg akkor nem túl ésszerű, ha a keretrendszer feladatait pár alap PHP függvénnyel mi is el tudjuk látni
A PHP alap függvényei és funkcionalitása nem változott. Az if, a function és társaik az 1.0-s verzió óta statikusak, aki meg egzotikus funkcionalitást használ, vessen magára.

Nekem meg egy hashtable.
Nem azt mondtam, hogy if-et kötelező használni, idézted is, amit írtam, hogy pár alap PHP függvénnyel. A hashtable is az 1.0 óta változatlanul benne van a programban.
33

Szeretném BlaZe álláspontját

smokey · 2017. Már. 30. (Cs), 09.24
Szeretném BlaZe álláspontját támogatni.

Random Silex project, írta smokey, részlet:

$app->patch('/users/{userId}/password', 'users.controller:updatePassword');
$app->put('/users/{userId}/images', 'users.controller:uploadImage');
$app->patch('/users/{userId}/contacts', 'users.controller:updateContacts');
$app->put('/users/{userId}/profile_images', 'users.controller:uploadProfileImage');
$app->get('/users/{userId}/images', 'users.controller:getImages');
$app->get('/users/{userId}/personal', 'users.controller:getPersonal');
$app->get('/users/{userId}/services', 'users.controller:getServices');
$app->get('/users/{userId}/remaining', 'users.controller:getRemaining');
$app->patch('/users/{userId}/services', 'users.controller:updateServices');
$app->patch('/users/{userId}/personal', 'users.controller:updatePersonal');
$app->delete('/users/{userId}/images/{imageId}', 'users.controller:deleteImages');
$app->get('/users/validation/email/{email}', 'users.controller:emailValidation');
$app->get('/users/{userId}', 'users.controller:get');
$app->put('/users/{userId}', 'users.controller:update');
A controllerem egy osztály, amibe be van injectálva egy user service. A controller action az actionönkénti service result alapján eldönti, milyen kimenete generál: 200, 201, 202, adott esetben elszáll egy exceptionnel, aminek 4xx státusza lesz.

Ha már az actionben van az alkalmazás, akkor tudom, hogy:
- A user nek van joga lefuttatni
- Valid az adat
- És rendelkezésre áll minden infó, hogy végbe menjen az action.

A service osztályba egyébként még be van injectálva ez az (repository osztályok, mailerek, logger, stb.)

A fenti kód egy REST API alkalmazás részlete. Ránézek és magas szinten látom, mi történik. Az URI-k erőforrásra mutatnak, nincs bennük ige, csak főnevek. Az ige a HTTP verb, ami gyakorlatilag megmondja, hogy mit fog csinálni egy adott erőforrássa. Üzleti értelemben látod mi történik. Hogy forráskód szinten mi történik, az más kérdés.

Látom az összes belépési pontot. Ezeken keresztül engedek be bárkit is. Interface, szerintem tök jó.

Jah, és mi nincs a kódban? Anonymus. Hogy ezt mi oldja meg? Egy jó kis függőség ;). Mi a kód előnye? A DI segítségével sikerült úgy megcsinálni, hogy controller szintől befelé nem függök a Silextől (Akkor miért használok Silexet? Mert rugalmas, és megfelelő módon oldja meg a problémámat). Az alkalmazás üzleti része egy függőség, ami composerrel van behúzva, gyakorlatilag natív PHP a megfelelő libekkel. Ott van még a Silex függőségként, a kettőből pedig kerekedik egy alkalmazás.

Mit értem el ezzel, van egy karbantartható, jól szervezett, TESZTELHETŐ alkalmazásom!

PUT vs PATCH, nem menőségből van ott. Ahogy a mellékelt ábra mutatja: PUT-tal a full objektumot módosítom, PATCH-el pedig csak annak egy részét. Technikailag és üzletileg is más.

Akár le is dokumentálhattam volna kód szinten, hogy mi mit csinál, de minek, mikor az a fenti pár kódsor ezt megteszi. Részletes dokumentáció pedig az API doksiban.
34

Kérdések

Hidvégi Gábor · 2017. Már. 30. (Cs), 14.38
Kérdések
  • Miért van itt is – mint Blaze kódjában – annyi redundancia? Egy kivételével az összes útvonal úgy kezdődik, hogy /users/{userId}, ugyanez igaz az users.controller-re is. Plusz információt nem hordoznak ezek az ismétlések, viszont az olvasást rontják. A Silexben lehetőség van csoportosításra, miért nem használod?

  • Miért vannak bármiféle logika nélkül összehányva az útválasztók? Semmilyen rendezőelvet nem látok, nincs prioritási sorrend (például users/{userId}, users/{userId}/personal, users/{userId}/profile_images stb.), nincsenek egymás mellett az ugyanahhoz az url-hez tartozó műveletek.

  • Továbbra sem értem a PATCH, PUT stb. közti különbséget. Az oké, hogy PATCH /users/userid/password, de miért PUT a /users/userid? Mert emellett PUT /users/userid/images, azaz kép feltöltésénél PUT metódus van. A felhasználót is feltöltöd?

  • A User objektum metódusainak nevei miért nem tükrözik az elvégzett műveletet? Mert a PATCH /users/userid/password mögötti művelet az updatePassword, de a PUT /users/userid-t a hasonló nevű users.controller:update végzi.

  • Miért jelenik meg az URL-ekben a felhasználó azonosítója? Én például munkamenetben tárolom, így jóval egyszerűbb a programom, mert nem kell kérésenként ellenőrizni, hogy kiről van szó, van-e jogosultság módosítani az adott erőforrást stb.

  • Miért jelenik meg a validációs URL-ben az emailcím? Nem fogják a keresők a validációs email-ben található validációs URL-t beindexelni?

  • Mihez kezd a felhasználó a HTTP státuszkódokkal? Ennek legfeljebb gépi kommunikációnál lehet jelentősége.

  • Miért vannak megkülönböztetve a HTTP igék és az URL-jeik? Itt arra gondolok, hogy a felhasználó szempontjából a következő történik: lát a kliensen (képernyőn vagy bármilyen adatszolgáltatón) egy adathalmazt, például a felhasználó adatait (GET /users/userid). Ehhez az alkalmazás készítője felsorol tevékenységeket, például módosíthatja őket (PATCH /users/userid). Miért kell külön felsorolni ezeket a módosító URL-eket? Az adott adathalmaz URL-je és a rajta végzett műveletek szorosan összetartoznak, és a listádból látszik is, hogy maga az URL ugyanaz GET és PATCH/PUT esetben is. Akkor biztosan routing probléma a PUT és PATCH HTTP igék kezelése?


Én hogyan oldanám meg?

A felsorolásodból látszik, hogy egyszerű megfeleltetéssel, hash táblával és egy ciklussal el lehet végezni a feladatot:
$url_ek = array(
  '/'        => 'userInfo',
  '/personal' => 'userPersonalInfo',
  '/images'   => 'userImages',
);
foreach (...)

Mivel a GET és a PUT/PATCH és társaik egy URL-en vannak, ezért a kérés feldolgozását magában a metódusban végezném:
//userInfo oldalon vagyunk
if (isset($_POST['akcio']) and $_POST['akcio'] === 'modositas') {
  ellenorizParameters();
  saveFelhasznalo();
  atdobAddress('/');
}

$adatok = getFelhasznaloInfo();
return 'akármi';

Így nincs szükség a HTTP igék miatt az URL-ek megkülönböztetésére.
35

Miért van itt is – mint Blaze

smokey · 2017. Már. 31. (P), 00.51
Miért van itt is – mint Blaze kódjában – annyi redundancia? Egy kivételével az összes útvonal úgy kezdődik, hogy /users/{userId}, ugyanez igaz az users.controller-re is. Plusz információt nem hordoznak ezek az ismétlések, viszont az olvasást rontják. A Silexben lehetőség van csoportosításra, miért nem használod?


Én sem szeretem a redundanciát, de a routoknál valahogy jobb szeretem látni a teljes képet ilyen módon.

Miért vannak bármiféle logika nélkül összehányva az útválasztók? Semmilyen rendezőelvet nem látok, nincs prioritási sorrend (például users/{userId}, users/{userId}/personal, users/{userId}/profile_images stb.), nincsenek egymás mellett az ugyanahhoz az url-hez tartozó műveletek.


Nem tudom, jó kérdés. Ez alatt mit értesz: nincsenek egymás mellett az ugyanahhoz az url-hez tartozó műveletek?

Továbbra sem értem a PATCH, PUT stb. közti különbséget. Az oké, hogy PATCH /users/userid/password, de miért PUT a /users/userid? Mert emellett PUT /users/userid/images, azaz kép feltöltésénél PUT metódus van. A felhasználót is feltöltöd?


Képfeltöltéskor PUT request szokott menni.

A User objektum metódusainak nevei miért nem tükrözik az elvégzett műveletet? Mert a PATCH /users/userid/password mögötti művelet az updatePassword, de a PUT /users/userid-t a hasonló nevű users.controller:update végzi.


Pontosítanék, UserController, nem User. Szerintem pont, hogy tükrözik.

Miért jelenik meg az URL-ekben a felhasználó azonosítója? Én például munkamenetben tárolom, így jóval egyszerűbb a programom, mert nem kell kérésenként ellenőrizni, hogy kiről van szó, van-e jogosultság módosítani az adott erőforrást stb.


REST APIról beszélünk, tehát nincs munkamenet, user id attól függetlenül van, JWT authentikáció segítségével. Ugyanazt a műveletet végrehajthatja egy felhasználó, illetve egy admin is. Ha adminnal vagyok belépve, és ő egy másik userhez akar képet feltölteni, akkor ilyen módon tudja megcímezni az erőforrást, vagyi az X userhez tartozó képek listáját, amibe bele PUT-tól egy képet.

Miért jelenik meg a validációs URL-ben az emailcím? Nem fogják a keresők a validációs email-ben található validációs URL-t beindexelni?


REST API, nincs indexelés. Ez egy regisztráció X-edik lépésében használt validációs pont.

Mihez kezd a felhasználó a HTTP státuszkódokkal? Ennek legfeljebb gépi kommunikációnál lehet jelentősége.


A felhasználó semmit, viszont a REST kliens hibakezelője már annál inkább sok mindent.

Miért vannak megkülönböztetve a HTTP igék és az URL-jeik? Itt arra gondolok, hogy a felhasználó szempontjából a következő történik: lát a kliensen (képernyőn vagy bármilyen adatszolgáltatón) egy adathalmazt, például a felhasználó adatait (GET /users/userid). Ehhez az alkalmazás készítője felsorol tevékenységeket, például módosíthatja őket (PATCH /users/userid). Miért kell külön felsorolni ezeket a módosító URL-eket? Az adott adathalmaz URL-je és a rajta végzett műveletek szorosan összetartoznak, és a listádból látszik is, hogy maga az URL ugyanaz GET és PATCH/PUT esetben is. Akkor biztosan routing probléma a PUT és PATCH HTTP igék kezelése?


Mert a felhasználó bizonyos részét (jelszó, személyes infó, kapcsolati infó) módosítani tök más logika, mint módosítani az egyéb más helyen tárolt felhasználói adatokat. Így egy 200 soros if halmaz helyett rendelkezésemre áll 4-5 olyan végpont, amiről ránézésre megmondom, hogy mit csinál.

Én hogyan oldanám meg?...


És így lett a spagetti. Egy idő után az ilyen megoldásokkal az a baj, hogy az alkalmazás minden rétegében ott lesz minden. Nem mondom, hogy minden esetben, de egy adatbázis lekérdezésért felelős osztályban $_SESSION használat ne legyen. Az nem oda való. Úgyanúgy egy controllerbe se legyen egy darab lekérdezés se.
36

Off: POST/PUT

Arnold Layne · 2017. Már. 31. (P), 01.06
Képfeltöltéskor PUT request szokott menni.

Az nem úgy szok' lenni, hogy új tartalmat POST-tal ozunk létre, meglévőt pedig PUT-tal írunk felül? A PATCH-ről most eltekintek az egyszerűség kedvéért.
37

Naggyából. Pontosabb, hogyha

smokey · 2017. Már. 31. (P), 08.06
Naggyából. Pontosabb, hogyha egy PUT-ot lefuttatsz sokszor, akkor nem szabad, hogy futásonként más eredményt adjon. Ha POST-olsz, akkor az minden lefutáskor más eredményt kell, hogy adjon.

Ettől függetlenül az én példám nem ezt tükrözi, jogosabb volna POST-tal fájlt feltölteni, és ahogy nézem elég sok helyen így javasolják. Régebben volt egy Amazon S3-as fájlfeltöltős story, ahol PUT requesttel kellett feltölteni (amit akkor egyébként én sem értettem, de elhittem a backendes embernek, hogy fájl felöltéskor jóvanazúgy'), innen maradt az emlék; rosszul.
55

Szvsz az ilyesmi tipikusan

inf · 2017. Ápr. 12. (Sze), 19.17
Szvsz az ilyesmi tipikusan kimehet konfig fájlba is, legalábbis nem nagyon szokott olyan extra lenni routing-ban, ami indokolja a függvény/metódus használatot.
58

A kohézió szerintem

BlaZe · 2017. Ápr. 12. (Sze), 22.23
A kohézió szerintem indokolja. Ha lehet, én egy helyen szeretném látni az url-t, és egyéb selector feltételeket, meg a feldolgozó kód egyértelmű referenciáját. A kód ad erre struktúrát, kiegészítést, és kész van hozzá a parser. Meg ez egy statikus dolog, configurálni nem igazán lehet.
59

Én úgy vagyok vele, hogyha

inf · 2017. Ápr. 12. (Sze), 23.28
Én úgy vagyok vele, hogyha már úgyis stringet kell megadni, akkor tökmindegy, hogy json-ban, vagy kódban van. A PHP meg sajnos ilyen... (Nem véletlen nem használom.)
38

A beillesztett kódod pont

BlaZe · 2017. Már. 31. (P), 08.35
A beillesztett kódod pont ugyanannyira unintuitív, mint a Silex, ránéz az ember, és törheti a fejét, hogy melyik paraméter mit jelent.
Nem kell, létezik convention. De fél óra alatt nevesíthető minden paraméter.

Tele van redundanciával, és nem is csodálom, ha ma már inkább letagadnád.
Az URL ne legyen már redundancia :) Amíg egy képernyőre kifér a routing ruleset full URL-lel, a csoportosítás csak ront az olvashatóságon.

Ráadásul a legszebb, hogy a háttérben ugyanúgy if-ek vannak.
Nem szükségszerűen. Egy hashtable csodákra képes.

Nem ezekkel van a baj. Smokey elég nagy betűkkel kiemelte a lényeget: TESZTELHETŐ. Na az én megoldásom sem az, bár kb fél óra alatt azzá tehető. A te megoldásod viszont nagyon messze van tőle. Ezért kellenek az ilyen "túlbonyolítások". Egyrészt hogy tesztelhető legyen, másrészt hogy ne egy refaktorálás vezesse egy business feature szállítási idejét.

A PHP alap függvényei és funkcionalitása nem változott. Az if, a function és társaik az 1.0-s verzió óta statikusak, aki meg egzotikus funkcionalitást használ, vessen magára.
Nem egyszer kellett hivatalos PHP függvény, vagy sokáig támogatott működés miatt változtatnom kódon anno. Már nem emlékszem rájuk szerencsére, csak hogy rendszeres volt. A PHP által dokumentáltan támogatott nyelvi eszközöket használni nem egzotikum.

Nem azt mondtam, hogy if-et kötelező használni, idézted is, amit írtam, hogy pár alap PHP függvénnyel. A hashtable is az 1.0 óta változatlanul benne van a programban.
Csak konzekvensen if mellett érvelsz, mert az jobb, meg gyorsabb, mint egy olyan struktúra, amiből hatékonyabb hashtable építhető.
39

Teszt

Hidvégi Gábor · 2017. Már. 31. (P), 10.27
Pontosan ki vagy mi akadályoz meg a tesztelésben?

A legjobb tudomásom szerint a teszt arra való, hogy egy szoftveregységre bemenő paramétereket eresztünk, majd ellenőrizzük, hogy a kapott adatok megfelelnek-e az elvártaknak.
40

Hogy adsz neki teszt

BlaZe · 2017. Már. 31. (P), 11.14
Hogy adsz neki teszt paramétereket? Hogy nézed, hogy az input paraméterek megfelelően vannak-e felhasználva? Hogy nézed, hogy a megfelelő controller, command van kiválasztva, az pedig a megfelelő input paramétereket kapta a dispatchertől? Hogy nézed meg esetleg, hogy bármi a controller által használt service-en milyen interakciók történtek, milyen belső állapotátmenetek mennek végbe? Ezek hiányában pedig hogy dokumentálsz a teszteddel?
41

Teszt

Hidvégi Gábor · 2017. Már. 31. (P), 12.32
Ha teszt módban van az alkalmazás, akkor teszt paraméterekkel dolgozunk, amelyek forrása lehet teszt adatbázis vagy statikus táblák. Ha nem megfelelő az egység kimenete (azaz hiba van), akkor végignézem a szükséges komponenseket és az adatfolyamot.
42

Ezzel még elég messze vagy az

BlaZe · 2017. Már. 31. (P), 13.35
Ezzel még elég messze vagy az effektív automata teszteléstől. A kérdés az, hogy hogyan tudsz az általad jónak tartott forrásra (sok if, primitív függvények, minimális absztrakció) a fentebb feltett kérdésekre megoldást adó automata teszteket írni? Másképp megfogalmazva: hogyan tudod a production kódbázisodat úgy futtatni tesztben, hogy a prod kód teljesen változatlan marad, mégis meg tudod figyelni a működését.
43

Miért?

Hidvégi Gábor · 2017. Már. 31. (P), 14.33
Miért lennék messze? Miért tartod elképzelhetetlennek, hogy automata teszteket írunk (unit, rendszer) az általam vázolt elvekkel?

Teszteknél nem foglalkozunk a működéssel, hanem azt nézzük, hogy az elvárt eredményeket kapjuk-e. Hiba esetén viszont a javítása közben már figyeljük, mivel mi történik.
44

Amit eddig mutattál kódot,

BlaZe · 2017. Már. 31. (P), 17.12
Amit eddig mutattál kódot, abban elég macerásnak tűnik a mockolás, spy-olás. A primitív függvényeknek is van függősége (más függvények), amit ha nem tudsz kimockolni, vagy spy-olni, akkor a unit tesztelés nehezen értelmezhető. Ezen kívül a sok elágazást tartalmazó függvények komplexitása olyan nagy, hogy igen bonyolult megtalálni a helyes teszt adatokat, amivel lefeded a lehetséges lefutásokat, ráadásul elég sok teszt eset is kell rá (ezért sem szeretjük a hosszú metódusokat).

Plusz nem mindig elég a black box tesztelés. Ha van egy belső állapotod (pl egy state machine), akkor arra kíváncsi leszel pl, hogy hogy változik az állapot az egymást követő inputokra és requestekre. Ez meg nem feltétlenül jelenik meg a kimeneten, vagy nem a belső reprezentációban.

De ha tudsz mutatni példát hogy csinálod, akkor lehet jobban megértjük egymást.
46

Példa

Hidvégi Gábor · 2017. Ápr. 9. (V), 16.05
Egy űrlapkezelő rendszeren dolgozunk, ami két rétegből áll, alul vannak a moduljaink, amelyek végtelenül egyszerűek, pár kilobájtosak, és csak annyi a feladatuk, hogy pár belső változót írnak, olvasnak.

Ezekre épülnek az eseménykezelők, kvázi API parancsok, amelyekkel az űrlapokat vezéreljük:

ellenoriz(
  'bejovo_adatok' => array(
    'esemeny'  => 'onclick',
    'formid'   => 'asd123',
    'nodeid'   => 'sdf872',
    'recordid' => '5207',
  ),
  'vart_adatok' => array(
    array(
      'fuggveny'    => 'urlapelem_letezik',
      'parameterek' => array('iop244', 'kla398),
      'ertek'       => true
    ),
    array(
      'valasz' => array('ertekek', 'iop244', 's0', 'kla398'),
      'ertek'  => 'kiírandó érték'
    ),
  ),
);

Itt az történik, hogy a bejövő kérésben megkapjuk egy űrlapelem koordinátáit, valamint azt, hogy rákattintottak, ezt a rendszerünk feldolgozza.

Ez után megvizsgálhatjuk a kapott adatokat, például a rendszerünk egy függvényét (urlapelem_letezik) meghívjuk a kapott paraméterekkel, és megnézzük, hogy a kapott érték megegyezik-e az 'ertek'-kel. Így közvetve láthatjuk az alkalmazás memóriatérképét, amiről akár dumpot is kérhetünk minden fázisban.

Ugyanígy lehetőség van a visszaadott válaszban túrkálni, ellenőrizhetjük, hogy a $valasz['ertekek']['iop244']['s0']['kla398'] megegyezik-e azzal, hogy 'kiírandó érték'.
47

Függőségek?

BlaZe · 2017. Ápr. 9. (V), 21.36
Ezt értem, de erre mondtam, hogy nem igazán tudod a függőségei nélkül tesztelni a függvényedet. Anélkül pedig sokmindent nem tudsz tesztelni. Ettől még persze hasznos, amit példának hoztál. De az jó, ha a függőségek viselkedését tudod szabályozni, illetve a függvényed interakcióit is tudod vizsgálni tesztből. Pl hogy mit csinál az alkalmazásod, ha eltűnik mögüle a DB connection, vagy bármilyen külső szolgáltatás. Hibát dob? Újra próbálkozik? Ha igen, hányszor? És mennyi időt várakozik az egyes próbálkozások között? Sőt... az idő múlását tudod-e pl tesztben befolyásolni? Tehát az újrapróbálkozások között eltelt időt ki kell várnod, vagy előre tudod tekerni az időt (tesztben ugyebár nem nagyon sleepelünk)? A fent kritizált túlbonyolított megoldásokkal (IoC és polimorfizmus, merthogy ezek együtt a lényeg az idézett kódban is), ezeket mind egyszerűen meg tudod tenni. Emiatt nem az egyszerűség a jó vezérelv a programozásban (általában).
48

Teszt

Hidvégi Gábor · 2017. Ápr. 10. (H), 09.21
Miért ne tudnám a függőségei nélkül tesztelni?

require_once ($teszt and $teszt !== 'db') ? 'db_teszt.php' : 'db.php';

Senki sem akadályoz meg, hogy bármikor lecseréljem a modulokat. Ha belegondolsz, ez pont az IoC, csak a sok-sok mellébeszélés nélkül.

Jelenleg egyébként timeout-tal dolgozunk, amit írsz, arra később lesz szükségünk, úgyhogy még nem foglalkoztunk vele.

Emiatt nem az egyszerűség a jó vezérelv a programozásban (általában).
Ebben száz százalékig biztos vagyok, hogy tévedsz. Occam borotvája: két identikus megoldás közül az egyszerűbbet célszerű választani – ez Murphy törvényéből következik.
49

Persze, ezt megteheted. Ha

BlaZe · 2017. Ápr. 10. (H), 18.40
Persze, ezt megteheted. Ha meg esetleg spy-olni akarsz, csinálhatsz test_db.php, prod_db.php fileokat, ahol mindkettő a _db.php-ban lévő _query() függvényt hívja meg hátul. Pár helyen esetleg prod kódból direktben is meghívják a _query-t, elvégre fordítási hibát nem okoz, tesztelni meg úgyse tudod, hogy azt hívták meg, vagy a "prod" függvényt. A test_db.php-t még programozni is tudod, elférnek a lokális adatok a globális contextben. Ha esetleg különböző helyeken szeretnél 2 viselkedést biztosítani (pl egyik helyen retry-osat, másik helyen azonnal hibát dobósat) akkor lehet még test_retry_db.php, prod_retry_db.php... Lehet minden file-t duplikálni, amit tesztelt függvény hív, lehet nagy közös state-et menedzselni az esetek között, meg az abból eredő hibákat nyomozni. És rá lehet mondani erre, hogy egyszerűbb. Aki a kritizált módszert használja, az meg kimockolja 2 sorban. Bocsi az iróniáért, de lásd meg, hogy ez nagyon nem adja azokat a lehetőségeket, amiket mondtam, és ami elsőre egyszerűnek tűnik, súlyosan belimitálhat.

Occam borotvájáról meg sokan leírták már itt, hogy nem döntési modell...
50

Kémkedés és borotválkozás

Hidvégi Gábor · 2017. Ápr. 11. (K), 13.58
A vázoltnál azért egyszerűbben oldottuk meg:

function felulir($_regi_fv, $_uj_fv) {
  rename_function($_regi_fv, 'regi_' . $_regi_fv);
  override_function($_regi_fv, '', 'call_user_func_array("' . $_uj_fv . '", func_get_args());');
}

felulir('db_kapcsolodas', 'db_kapcsolodas_teszt');


Occam borotvájáról már korábban beszéltünk; azt kell csak eldönteni, hogy mi az egyszerűbb megoldás. Ha van egy kész keretrendszered/rutinkönyvtárad, ami elvégzi a feladatot, akkor valóban őrültség újat írni. Mi is használunk ilyet, például PDF nyomtatásra vagy SQL parse-olásra. Ezek elvégzik a feladatukat, szerencsére egyik formátum sem változott az évek során, ezért nincs ok hozzányúlni.

Ezzel szemben az általunk használt Ext.js keretrendszer – a licenszproblémáktól eltekintve – folyamatosan csak problémát okozott, jó példa erre a beépített kombobox, aminek a nettó forráskódja több mint nyolcszáz soros, hat-nyolcsoros öröklődéssel. A legújabb i7 is letérdelt, amikor olyan űrlapokat kellett kirajzolni, amelynek minden sorában volt hat-nyolc ilyen elem. Ez még mondjuk elviselhető lett volna, de az nem, hogy állandóan javítani kellett, mert túl összetett volt, és mindig valami baj volt vele.

Fogtam, újraírtam százhúsz sorból egy délután, és most a legbonyolultabb űrlapunk renderelése is 150ms alatt van egy Atom processzoros gépen.

Gondolj csak bele: hány hibát lehet véteni nyolcszáz, és hányat százhúsz soron?
51

Végtelen

Pepita · 2017. Ápr. 12. (Sze), 08.33
Ezzel az összehasonlítással nagyon nem értek egyet:
Gondolj csak bele: hány hibát lehet véteni nyolcszáz, és hányat százhúsz soron?

A hibák száma, súlyossága nem következik a sorok számából. Ha így lenne, akkor még mindig statikus html oldalakat gyártanánk, egy multinak is max 5 oldal lenne a teljes honlapja. Nehogy túl sok sor legyen... :)

A hibák száma, súlyossága elsősorban a fejlesztőtől függ, de jelentősen hatnak rá a külső függőségek (másik szar kód pl) is.
Nyilván ugyanaz a fejlesztő több soron több "darab" hibát tud ejteni, de gondolj bele abba is, hogy ha "igyekszem", js-ben simán követhetek el 120 soron annyi hibát, mint Te 800-on... :-D
52

Statisztika

Hidvégi Gábor · 2017. Ápr. 12. (Sze), 16.12
ratio of bugs per line of code
Industry Average: "about 15 - 50 errors per 1000 lines of delivered code."
57

Ez átlag. Benne van a 0 és az

BlaZe · 2017. Ápr. 12. (Sze), 22.17
Ez átlag. Benne van a 0 és az 1000 hiba / 1000 sor is. Annál fogva, hogy csak átlag, pont Pepita állítását támasztja alá: az egységnyi kódbázisra eső hibák száma nem a sorok számától függ, hanem a fejlesztőtől ÉS a fejlesztési módszertan minőségétől. Továbbá teljesen ignorálja a kód felhasználóinak a számát, a lefedettséget stb. Érdekes szám, de kb ennyi.
56

Ez semmiben nem más, mint

BlaZe · 2017. Ápr. 12. (Sze), 22.04
Ez semmiben nem más, mint amit mondtam, csak máshogy van implementálva. Kaptál egy merev struktúrát, ami pont amiatt feszít, amiért az általad antikrisztusként kezelt öröklődés: baromi rugalmatlan, csak hierarchikusan tudsz funkcionalitást bevezetni. Kvázi gyártottál magadnak egy öröklődést a nyelvi support megkerülésével, annak garanciái és támogatása nélkül. Csak még rugalmatlanabb, mint az öröklődés, és átláthatatlan 1-2 mélység felett. 3 file-lal odébb már azt sem tudod melyik az eredeti függvény, melyik a dekorált, és ha szeretnél még dekorálni, melyik sok aláhúzásos nevűt is kéne override-olni. Teljesen követhetetlenné válik ez a módszer. Code reviewra gondolni se merek. Megjegyzem, ettől még a dekorálást meg kell írnod valahogy.

Szerintem meglepődnél, ha ezeket a módszereket olyan helyen próbálnád alkalmazni, ahol van több fejlesztő csapat, neadjisten fluktuáció is, meg több lokáció. Ott derül ki igazán melyik módszerek működnek, melyek nem.

Occam: Javaslom ismerkedj meg döntési modellekkel. Nem véletlenül vannak kifejlesztve. Occam borotvája nem döntési modell továbbra sem. Ha az lenne, nem lenne rá szükség, hisz a döntés trivialitásra redukálódna, opciók nélkül.