Szerintem egy függvény (alprogram) megfelelő hossza

Címkék

Pár sor (á lá Clean Code)
16% (50 szavazat)
Egyetlen "kontrol struktkúra" (if, for, stb.) vagy bekezdési szint (indentation level)
7% (21 szavazat)
Férjen ki a képernyőre
38% (118 szavazat)
Tudja betölteni a szövegszerkeszőm a RAM-ba
15% (47 szavazat)
Nem írok függvényeket, csakis goto!
6% (18 szavazat)
Csak az eredmény érdekel
17% (53 szavazat)
Összes szavazat: 307

Hozzászólások

Izé... szép-szép a clean code, de amikor az ember szétszed egy 50 soros függvényt 3 darab 15-25 soros függvényre, hogy clean code szemüveggel "szebb" legyen, ugyanakkor ezzel az egész elveszti az áttekinthetőséget, az nem biztos, hogy jó dolog... a másik probléma, hogy nincs egzakt határ arra, hogy hány sortól "szebb", ez függ attól, hogy éppen mi a metódus dolga és milyen az algoritmus megvalósítása.

Nem a sorok száma számít, hanem az absztrakciós szintek száma.
Egy függvény = 1 művelet, amely azonos absztrakciós szinten lévő dolgokat használ.
Aka composed method.
Lehet, hogy 50 sor így egy függvény, de lehet, hogy 3. Nem a sorszám a lényeg, hanem az absztrakciós szint.

A CC ezen szekciója sok mindenről szól, nem csak a LOC-ról. Aki csak annyit lát a CC függvényekről szóló részében, hogy LOC, az pont a lényeget nem látja.
Nem csak a sorok számáról szól. Hanem arról is, hogy "do one thing", amiből következik az egy absztrakciós szint is.

A CC harmadik fejezetében így végződik a Small! fejezet:
"Each told a story. And each led you to the next in a compelling order. That’s how short your functions should be!"
A lényeg nem a sorok száma, hanem a "telling a story" meg "leading to the next".
És akkor utána rátér a többi szabályra:
"FUNCTIONS SHOULD DO ONE THING . T HEY SHOULD DO IT WELL .THEY SHOULD DO IT ONLY ."
Majd:
"In order to make sure our functions are doing “one thing,” we need to make sure that the
statements within our function are all at the same level of abstraction."
És a conclusion részben:
"But never forget that your real goal is to tell the story of the system, and that the functions
you write need to fit cleanly together into a clear and precise language to help you with
that telling."

Baromira nem az a lényeg, hogy a függvényeid nem lehetnek 6 sornál hosszabbak. Aki csak ennyit lát, ezt a mechanikus szabályt, az nem érti ezt az egész fejezetet.

Speciel pontosan ő is ezt mondja:
https://www.martinfowler.com/bliki/FunctionLength.html

"The argument that makes most sense to me, however, is the separation between intention and implementation. If you have to spend effort into looking at a fragment of code to figure out what it's doing, then you should extract it into a function and name the function after that “what”. That way when you read it again, the purpose of the function leaps right out at you, and most of the time you won't need to care about how the function fulfills its purpose - which is the body of the function."

A kiemelt résznek pont a lényege, hogy egy függvény tartalmazzon egy absztrakciós szintet - ne a hogyant, hanem a mit írja le. Majd az eggyel alacsonyabb absztrakciós szint leírja a hogyant.
És ő pont ebből vezeti le, hogy ha ezt az elvet tartod szem előtt, akkor baromi rövid függvényeid lesznek. Hogy úgy mondjam, ez csak egy side effect. Egy példát is mutat erre:
"The fact that size isn't important was brought home to me by an example that Kent Beck showed me from the original Smalltalk system. Smalltalk in those days ran on black-and-white systems. If you wanted to highlight some text or graphics, you would reverse the video. Smalltalk's graphics class had a method for this called 'highlight', whose implementation was just a call to the method 'reverse'. The name of the method was longer than its implementation - but that didn't matter because there was a big distance between the intention of the code and its implementation."
Létezett egy függvény, a highlight, amely csak egy reverse-t hívott, egy sorosan. A lényeg az volt, hogy a highlight mint absztrakció létezett a rendszerben, és ahol kellett, ott highlight-ot hívtál, nem közvetelnül reverse-t, és nem is kellett tudnod, hogy a highlight implementációja egy reverse valójában.

Majd ugyanitt
"Small functions like this only work if the names are good, so you need to pay good attention to naming. This takes practice, but once you get good at it, this approach can make code remarkably self-documenting. Larger scale functions can read like a story, and the reader can choose which functions to dive into for more detail as she needs it."
Megint ugyanaz az elv: a függvény egy story.

De nem azt mondja, hogy rossz, hanem starts to smell. A hosszú függvényeknél nagyobb az esélye arra, hogy a két fontosabb szabályt: do one thing, meg one abstraction level megsérti.
De ez nem jelenti azt, hogy ne lehetne 8 soros kódra igaz, hogy do one thing meg one abstraction level.
Ezért mondom, hogy aki LOC-ot néz, az tényleg nem értette meg ezt az egészet, csak keres valami mechanikus kapaszkodót, amire lehet Sonar rule-t írni.

>Larger scale functions can read like a story, and the reader can choose which functions to dive into for more detail as she needs it.
Nekem is nagyon tetszett először ez az elv amíg el nem kezdtem gyakorolni. Sajnos a gyakorlatban az van, hogy mindegyikbe le kell menni és a tizedik kétsoros függvény után elfelejtem, hogy miről is szól a "story".

Szerintem az a helyzet, hogy a tapasztalatot semmivel sem lehet helyettesíteni. Olvashatsz akárhány CC könyvet meg kell érzed a bőrödön, hogy milyen egy több 100k soros kódbázison dolgozni, hogy tudd mennyi kód kell menjen egy függvénybe. Tapasztalat párosítva a review-al ugyancsak tapasztalt kollégáktól a killer kombo szerintem. Egy bizonyos tapasztalati szint után az ilyen szabályok mint a CC, pláne ha fanatikusok ráderőltetik csak rontják a produktivitást és a kód minőségét. Az XX% os unit test coverage nevű lószar mítoszba inkább bele se megyek.
--
:wq

mindegyikbe le kell menni és a tizedik kétsoros függvény után elfelejtem, hogy miről is szól a "story".

Ha jól van csinálva, akkor ahhoz, hogy tudd, hogy miről is szól a "story", egy szintet kell megértened és egyikbe se kell lemenned.

Szerintem az a helyzet, hogy a tapasztalatot semmivel sem lehet helyettesíteni.

Egyetértek! ;-)

Tapasztalat párosítva a review-al ugyancsak tapasztalt kollégáktól a killer kombo szerintem.

Nagyon egyetértek!

Egy bizonyos tapasztalati szint után az ilyen szabályok mint a CC, pláne ha fanatikusok ráderőltetik csak rontják a produktivitást és a kód minőségét.

A review-knak épp az lenne az egyik lényege, hogy a tapasztalt kolléga megmutatja, hogyan lehet olvashatóbbá, egyszerűbbé tenni a kódot. Alapvetően az lenne a jó, ha az első verziót mindenki úgy írná meg, ahogy szerinte a legolvashatóbb és legegyszerűbb a kód, vagy legalábbis arra törekedett ;-) Aztán majd a review-k során alakítanak rajta és az így nyert tapasztalattal egyre jobb kódok készíthetők.

Szerk.:
A draw-s példánál, ha egy picit is alkalmazták volna a CC szabályait, akkor esetleg lenne valami lövésünk, hogy mit csinálhat a kód. Alig pár soros, nagyon sok vezérlőszerkezet sincs benne, mégse tudunk róla semmit:
- mit csinál ez a függvény általánosságban,
- mit csinálnak a draw függvények (talán rajzolnak valamit),
- mit jelentenek az egyes szám stringek ("1", "2", ...),
- mit jelentenek az egyes state-ek (state1, state2),
- mit vezérelnek az egyes state-ek,
- az egyes draw-k között van-e kapcsolat,
...

Ha alkalmazva lenne néhány CC elv, akkor sokkal érthetőbb lenne a kód. Bizonyára igazad van, és egy tapasztalatlan kolléga a CC elvek nem megfelelő használatával tudna rossz kódot készíteni, de nem hiszem, hogy ennél a mostaninál sokkal rosszabb lenne :-)

>Ha jól van csinálva, akkor ahhoz, hogy tudd, hogy miről is szól a "story", egy szintet kell megértened és egyikbe se kell lemenned.
A kulcsszó itt a "story". Valóban, ha csak felületesen szeretnéd megérteni, hogy miről szól a kód akkor ennyi elég. De ha módosítani kell akkor legtöbbször mélyre le kell menni, hogy megértsd, hogy a sok mellékhatásnak milyen hatásaik vannak egymásra. Sajnos még nem dolgoztam olyan kodbázissal ami annyira jól lett volna megírva, hogy ez ne lett volna szükséges.

Én úgy vagyok a CC-vel, hogy az egy ideális világot ír le, ahol a teljesítmény és a határidők nem számítanak. Én mint földön élő fejlesztő nem tudom átvenni csak úgy az ott levő iránymutatást, max kiszemezgetem belőle a hasznos tanácsokat. Elég szkeptikus vagyok azokkal szemben akik szigorúan át akarják ültetni a gyakorlatba.
--
:wq

Te miről beszélsz?

Immutable módon is mindent meg lehet csinálni, lásd Haskell. Én még csak erről se beszélek, csak arról, hogy ahol nem szükséges ott feleslegesen bonyolítjuk el az életünket a mutability-vel.

A két véglet között nagyon sok lehetőség van:
Minden immutable (0%) --> ahol szükséges csak az mutable --> fele ilyen, fele olyan --> nagy része mutable --> minden mutable (100%).

A legjobb a 0% mutablitiy lenne, de ahhoz egyedi nyelv és valamennyi kompromisszum kell. A legrosszabb a 100% mutability és leginkább ilyen módon történik a fejlesztés. Tudom, hogy ezzel sokan nem értetek egyet, ezért is nagy a rákfene ;-)

Semmi baj nincs a mutabilitással, anélkül nem is létezne kód.
Csak éppen korlátot kell szabni a mutabilitásnak.

Ahogy a strukturált programozás és a "goto considered harmful" a vezérlésátadásra adott korlátokat, emiatt nehezebben állhat elő olyan kód, ami hibás (persze még így is sok hibás logikás kód van, de gotoval még szarabb lenne a helyzet).

Hasonlóan a state módosítására is kell valami eszköz, ami korlátot ad, például úgy, hogy maguk az objektumok immutable-k, és ha módosítani akarsz valamit, akkor létrehozol egy módosított másolatpéldányt.
Ennek az az értelme, hogy például a "copy constructorban" tudod vizsgálni a class invariantokat, és nehezebben fordulhat elő olyan, hogy egy objektumnak invalid állapota van, mert a sok-sok egymástól távol lévő mutator hatása káoszt okoz.
Persze hasonlóan, minden setterben lehetne vizsgálni a class invariantokat. Vagy temp objektumokkal (akár builder patternnel) dolgozni, és az új objektumot egy menetben, a builder állapota alapján létrehozni.
Stb.

Van ennek értelme, csak ésszel kell használni, és tudni, hogy mit áldozunk fel (egy kis teljesítményt) mire (kevesebb lehetséges side effectre).

Hogy másként mondjam: a strukturált programozás szabályozott kereteket ad a végrehajtás alatt lévő kód változásának módjaira vezérlési szerkezetekkel.
Az immutability meg szabályozott kereteket ad memóriában lévő adat változásának módjaira.

"Te miről beszélsz?"

Arról, hogy ha az ember kizárja az életéből és a munkájából a "nemszeretem" dolgokat, akkor könnyű szép dolgokat alkotni.

"Immutable módon is mindent meg lehet csinálni, lásd Haskell."

Mutass egy immutable hardvert... :)

Arról, hogy ha az ember kizárja az életéből és a munkájából a "nemszeretem" dolgokat, akkor könnyű szép dolgokat alkotni.

Szép dolgokat alkotni szerintem nehéz, főleg elsőre az.
Az adott feladat, eszközök és elvárások behatárolják, hogy mit és hogyan lehet megcsinálni, de tetszőleges esetben lehet a lehetőségekhez mérten a "legszebbre" vagy csak "szebbre" törekedni.
Azért is írtam a második példádra, hogy "szebb" és elfogadható, mert ott már a lehetőségekhez mérten (performancia, többlet munka) már lehet az a megfelelő absztrakciós szint.

Mutass egy immutable hardvert... :)

A legtöbb hardver immutable, nagyon kevés változik meg. ;-)

Gondolom tudod mi a különbség az immutable referencia és az immutable érték között.

Röviden (java):


Map<String, String> memory          // mutable reference, mutable value
final Map<String, String> memory    // immutable reference, mutable value
BigDecimal memory                   // mutable reference, immutable value
final BigDecimal memory             // immutable reference, immutable value

A fentiek alapján pl. az egyszer írható CD teljesen immutable, a CD hardvere sem változik és a rajta tárolt adat sem változik meg (immutable reference, immutable value).
A memória esetén pedig a memória hardvere immutable (nem változik), a rajta tárolt adatok megváltozhatnak (immutable reference, mutable value).

Ezt én is szeretném, de eddig kettőből kétszer nem sikerült egy 17 soros programot leimplementálnod komoly hiba nélkül, pedig elvileg azt akartad alátámasztani, hogy kevesebb hibát lehet elkövetni egy jobban áttekinthető formában...

...aztán meg össze-vissza beszélsz, adathordozókat nevezve hardvernek, miközben szerinted immutable egy hardver, ha fizikailag nem változik... gondolom benne az elektronok se mozognak innen-oda, onnan-ide, ugye? Ennyi erővel bármilyen forráskódból fordított bináris is immutable, mert nem változik, nem? Ezek után miről akarsz értelmes módon beszélgetni?

Eszembe jutott egy gondolat. Nem a fentiekbe akarok belekötni, inkább hozzáfűzni.

Ugyebár létezik a rubber duck debugging nevű dolog.
Meséld el a kollégádnak/egy virágnak/egy kávésbögrének/egy gumikacsának/, hogy mit csinál a kód, meg gondold át, hogy mit kellene csinálnia, és akkor rájön az ember, hogy miért is hibás a kód.
És sok esetben észervettem, magamon is, kollégákon is, hogy boldogan jönnek ide, hogy köszi az ötletet, tényleg működik a módszer, mert rájött, hogy mi a hiba a kódban.
Majd elkezdi mesélni, hogy: "látod, itt az 55-60-ik sorban csinálom azt, hogy...". És mi lenne, ha ezt az 5 sort kiszervezné egy olyan nevű függvénybe, ami pont ezt írja le?
Hasonlóan, amikor egy bonyolult függvényrészletben van hiba, egy jól körülírható, saját névvel rendelkező kódrészletben, akkor az egy code smell: kiszervezhető függvénybe, és a hívóban már csak a magasabb szintű absztrakció látszik - mert erre kíváncsi valójában a hívó, nem a függvény törzsére.
A draw példánál maradva, könnyen lehet, hogy _Franko_ a kérdésemre azt fogja mondani (vagy valami hasonlót):
- ez a függvény a Draw1-Draw3 részben kirajzolja egy sprint hátterét meg körvonalát (akkor miért nem egy ilyen nevű függvényben van ez leírva, ha amúgy saját magadnak így fogalmazod meg)
- ez a függvény az if(state1) részben kirajzolja az overlayt, ha ki kell rajzolni
stb.

Remélem érthető.

Egy nagyon fontos gondolat tartozik még ehhez: a kód kommentelés.
Ugyebár sokan azt várják el, hogy a programozó írja le a kommentben emberi nyelven, hogy mit csinál a kód. Ez feltételezi azt, hogy emberi nyelven a programozó jobban meg tudja fogalmazni azt, mint programozási szerkezetek (metódusok, elágazások stb.) használatával. Miért is gondoljuk azt, hogy ha valaki nem tudja érthetően leírni a kódban, hogy mit cisnál a kód, akkor majd emberi nyelven érthetően tudja leírni?
Pedig általában itt arról van szó, hogy egy absztrakciós szint hiányik: a kommentben leírt emberi nyelvi mondatokat meg kell fogalmazni a kód szintjén is.
Tipikus példa:


// if trader can view this portfolio
if(portfolioIdsByTraderId.contains(traderId)){...}

Hát akkor itt bizony hiányzik egy absztrakciós szint, hiányzik egy fogalomalkotás, egy metódus.
Sokkal jobb,ha ezt írja az ember:


if(trader.canView(portfolio)){...}

Majd szépen, a

Trader.canView

implementáció már megfogalmazza konkrétan, hogy hogyan is dől el, hogy "trader can view this portfolio".

Hasonló elv még, és ide tartozik, spt, valójában erről szól a separation of mechanism and policy is.

A gumikacsa módszer tényleg működik. Én egy tanácskérő emailt szoktam írni és mire a végére érek általában megkapom a választ és el se kell küldjem.

Itt jön be a tapasztalat. Amit leírtál mind igaz és egyetértek. De van egy vékony vonal azok között az esetek között ahol ez megéri és ahol ez nem éri meg mert már túllő a célon és rontja az olvashatóságot mert az információ ami ahhoz kell, hogy megértsd a kódot szét van szórva.
Nem mindig lehet egy függvénynévnyi helyre besűríteni, hogy mit is csinál az az 5 sor kód és ilyenkor az eredeti függvényből ahonnan ki lett emelve információ veszik el.

A kommentek is tudnak nagyon hasznosak lenni. Tudom, hogy Fowler úr nem szereti őket de én szeretem olvasni, hogy a kód szerzője milyen "pre" és "post" feltételekre támaszkodott amikor a kódot írta. Sajnos a nyelvek amikkel dolgozunk tökéletlenek és nem mindig lehet vagy megendegett (teljesítmény miatt), hogy ezeket kódban kifejezzük.

Sokat szajkózom a teljesítményt és bár tudom, hogy sok helyen ez nem szempont, de ahol én dolgozom ez nagyon fontos és van olyan hot path ahol egy virtual callt vagy egy osztást is jól meg kell indokolni.
--
:wq

Igen, vannak olyan folyamatok, amiket nehez elnevezni. Altalaban ilyenkor kiderul, hogy mar alapbol rosszul neveztem el az osztalyt, vagy Single Responsibility Principle violation van a kodomban. (Megkeresni, refactor, ha nem megy, akkor segitsegkeres)
Es egyetertek, hogy szelsoseges esetekben szukseg van olvashatosagot ronto kodoptimalizalasra, esetleg kommentekre. (ld: Clean Coder Blog - Necessary Comments)
Ekkor valoszinuleg a tesztek fogjak erthetove tenni a rendszert. Formalisan leirjak, hogy mire kepes a rendszer, es mik a hatarai (Amit nem teszteltunk, az nem letezik).
Ha nincsenek tesztek, akkor onnantol kezdve az a kod egy veszett fejsze nyele, mert az eredeti fejleszton kivul nem sokan fogjak modositani/javitani. (job security FTW?)

De ezek _szelsoseges_ esetek. A legtobb programozónak nem kell leimplementalnia az strcpy-t ugy, hogy a leheto legoptimalisabb legyen, mert nem fogjak annyiszor hasznalni. (Singleton patternbol sem kell rogton a DoubleCheckedSingleton-t implementalni)
Ha megiscsak szukseg lenne ra, hogy gyorsabb legyen a kod, akkor a refactor + kodoptimalizalas nincsen megtiltva, A tesztek garantalni fogjak, hogy ne rontsa el a mar meglevo viselkedest.
Ugy velem, hogy a kodoptimalizalas az utolso lepes a fejlesztesben (aka "Make it work. Make it right. Make it fast" - Kent Beck)

A CC nem csak szabalyokbol all, hanem szepen felepitett magyarazatokbol is.
Tenyleg ajanlom, hogy olvassatok bele, mert a sajat boromon tapasztalom, hogy mekkora problema, ha ezeket a tanacsokat mellozik a fejlesztok.

utoszo:
Fejlesztettem egy "AI"-t (agent-et) egy jatekhoz, es par honap piheno utan, mikor visszatertem hozza, el kellett dobnom az egeszet, mert nem tudtam kiboviteni. (ennyi ido alatt elfelejtettem, hogy mit es mit nem csinal)
Ujrairtam az egeszet par nap alatt TDD-ben. Megint eltelt par honap, es nem volt problema a bovitessel, mert egyaltalan nem kellett foglalkoznom azzal, hogy "mit ronthatok el". Minden okozott hibat azonnal jeleztek a tesztjeim.
Atstrukturaltam a kodot, es odaig jutottam, hogy egy-egy uj viselkedesi minta (feature) mar nem ronthatja el a tobbi, mar definialt viselkedest.
---
Lambda calculus puts the fun into functional programming

+1

Ugy velem, hogy a kodoptimalizalas az utolso lepes a fejlesztesben (aka "Make it work. Make it right. Make it fast" - Kent Beck)

Egyetértek, ráadásul sok esetben az optimálisabbnak hitt kód a rosszabb teljesítményű. Így a mérés is nagyon fontos, ha teljesítményre akarunk optimalizálni.

A CC nem csak szabalyokbol all, hanem szepen felepitett magyarazatokbol is. Tenyleg ajanlom, hogy olvassatok bele, mert a sajat boromon tapasztalom, hogy mekkora problema, ha ezeket a tanacsokat mellozik a fejlesztok.

Jó volna, ha tényleg minél többen elolvasnák és el is kezdenék gyakorolni a tanultakat!

Na, ezzel az a probléma, hogy van, aki szerint ha van egy

public Kiskacsa GetKiskacsa(int id) {...} 

metódusod, akkor túl nagy elvárás, hogy anélkül, hogy oda lenne írva külön egy "visszaadja az ID azonosítójú kiskacsat", akkor rájöjjön, hogy mit csinál a metódus, csupán a szignatúráját nézve.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

A jó komment nem írja le az egyértelmű, triviális (obvious) dolgokat. Mint ahogy értékeadáshoz, ciklushoz, netalántán függvényhíváshoz sem írunk önmagában kommentet.
Amit kommentezni kell, mert névben nehéz lenne kifejezni:
- hogyan csinálja a kód, amit csinál
- miért csinálja a kód azt, amit csinál (akár egy hivatkozás a specifikációra, amit megvalósít)
- milyen side effectek vannak (főleg egy getternél)

Ugyanígy ezért vannak patternjeink, közös szótárunk arra, hogy ha valaki szakmabeli azt mondja, hogy Visitor, Observer vagy Proxy, akkor mindenki tudja, mit akar mondani.
Persze nem mindenki, aki programot ír, az szakmabeli. Mint ahogy nem mindenki villanyszerelő, aki be tud szerelni egy fali csatlakozót. Meg nem lesz üzemeltető az, aki össze tud rakni egy asztali gépet.

Ok, de egy "Foo GetFoo(int id)"-t nem tudok tovább egyértelműsíteni. Illető szerint túl nagy elvárás volt, hogy fejlesztőként (ok, juniorként) elvárjam, hogy a névből rájöjjön, hogy mit csinál az a függvény.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Mindig voltak és mindig lesznek... néha egyforma dolgot mondanak, akkor azért érdemes rajta elgondolkodni, néha meg a dirty hack a célravezető.

És igen, lehet csiszolni a kódot végtelenségig, csak akkor meg bejön a másik oldalon a lean menedzsment, hogy termel-e értéket az ügyfélnek, amit csinálsz. Az arany középút meg járhatatlan mocsár a különböző filozófiák tópartján pontos jelzőkarók nélkül.

Ha egy eleg jol definialt stilust ismer alaposan es kovet a csapat minden tagja, akkor a minoseg neveben sosem fogjak azt a vegtelensegig csiszolni, sot, a "kodszepites" nem vesz el extra idot. Itt jonnek a kepbe ezeknek a "megmondoembereknek" a bolcsessegei. Ha a csapatnak nincs egy ilyen szentirasnak tekintett merceje, akkor vagy mindenki hanyag, senkit sem erdekel a minoseg, vagy mindenkinek megvan a maga velemenye, ami feszultseget szul.

Azert keszultek mar tanulmanyok bizonyos modszerek hatekonysagarol, vannak ott jelzokarok boven. Pl. hatekony unit testek hosszabb tavon megterulnek. Egy projektben viszont, ahol ketes, hogy befut-e, kezdetben nem erdemes ebbe fektetni, a minosegre raer majd 2.0-ban figyelmet forditani.

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

Nézd, tavaly is kellett valamennyit fejlesztenem Atlassian termékekhez és ez miatt bele kellett néznem pár termékük forrásába. Na, olyan fos forrást ritkán láttam, mindegyik termékük másképp van felépítve, másképp működik, satöbbi, pedig az Atlassian a scrum, meg a kanban meg a lean meg a minden management zászlóvivője, a cég értéke már egy ideje meghaladta a 10 milliárd dollárt, de valahogy fontosabb nekik az értékteremtés, mint a mindenféle clean code és egyéb szöszmögések, pedig pénzük és idejük lenne rá.

Elhiszem, de a jelenlegi helyzetbol miert egyertelmu szamodra, hogy ha tobb idot forditottak volna minosegre, nem lennenek elorebb? Vagy a jovoben nem lenne kevesebb szivas?

Volt szerencsem ket nagyobb projekthez, ahol annyira zagyva volt a kod, hogy a fejlesztok valosaggal feltek belepiszkalni, egy trivialisnak tuno feature vagy bugfix tobbhetes melo volt...

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

"Elhiszem, de a jelenlegi helyzetbol miert egyertelmu szamodra, hogy ha tobb idot forditottak volna minosegre, nem lennenek elorebb? Vagy a jovoben nem lenne kevesebb szivas?"

Miért vagy ebben ennyire biztos? Én nem nagyon láttam arra egyértelmű példákat, hogy a sok pénzt hozó programok és a mindenféle fejlesztési irányzatok betartása között lenne bármilyen összefüggés.

Ez az egész terület kicsit olyan, mint ahogy a "Hogyan lehetsz mocskosul gazdag" jellegű könyvek szerzői nagyrészt abból lettek mocskosul gazdagok, hogy írtak egy könyvet a témában. Martin Fowler se azért lett mocskosul gazdag és ismert, mert mocskosul jó programokat írt, amelyek annyira bejöttek az ügyfeleinek, hogy mocskosul sok pénzt voltak hajlandóak érte fizetni, hanem mert jól hangzó elvekről adott elő...

"Volt szerencsem ket nagyobb projekthez, ahol annyira zagyva volt a kod, hogy a fejlesztok valosaggal feltek belepiszkalni, egy trivialisnak tuno feature vagy bugfix tobbhetes melo volt..."

Én is láttam már ilyet. Nincs éles határvonal, hogy mikortól jó és mikortól nem jó. És ami kód mondjuk jó volt egy éve, az lehet, hogy most már nem jó, teljesen más okokból. Láttam már nagyon szép monolitikus kódot és nagyon ronda, ám hangzatos elvek mentén fejlesztett kódot.

"Miért vagy ebben ennyire biztos?"

En nem vagyok benne biztos, de ugy tunik, hogy te igen, erre celoztam.

Abban sem vagyok biztos, hogy a megmondoemberek ajanlasai helyesek, optimalisak, csak az a helyzet, hogy SE nagyon gyerekcipoben jar. A megmondoemberek meg legalabb aktivan foglalkoznak a temaval es nyujtanak kapaszkodot, nelkuluk mindenki menne a maga feje utan.

"Láttam már nagyon szép monolitikus kódot és nagyon ronda, ám hangzatos elvek mentén fejlesztett kódot."

Es mi alapjan itelted meg, hog szep-e? A sajat elveid alapjan, amelyek lehet, hogy ertelmesebbek azoknal a hangzatos elveknel, de az is lehet, hogy csak masak...

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

"Abban sem vagyok biztos, hogy a megmondoemberek ajanlasai helyesek, optimalisak, csak az a helyzet, hogy SE nagyon gyerekcipoben jar. A megmondoemberek meg legalabb aktivan foglalkoznak a temaval es nyujtanak kapaszkodot, nelkuluk mindenki menne a maga feje utan."

Én láttam mostanában pár cég forráskódját kicsitől a mamutig, széptől a rondáig... igazából nem láttam korrelációt az üzleti sikeresség és a forráskódok minősége között. Sőt, inkább fordított arányosságot láttam: a legnagyobb gányolások voltak a legsikeresebb cégeknél.

"Es mi alapjan itelted meg, hog szep-e?"

Ránézésre. Mondhatnám inkább azt, hogy mennyire átlátható, hogy mennyi idő kell ahhoz, hogy megértsem a működését. A legkuszább források azok voltak, ahol arra törekedtek, hogy nulla legyen a duplikáció, hogy sok kis függvény legyen, hogy jó hosszú változóneveket adjanak és a többi... csak közben elveszett a lényeg: az olvasható kód, amelyet nagy biztonsággal lehet módosítani.

Ha már olvasgatunk valamit, az nagyon jó, de ritka!
A legtöbben hallomásból ismerik ezeket az elveket is.
Ebben a topikban is láthatjuk, hogy van olyan, aki "Bob bácsi" (Clean Code) és Martin Fowler által e témában írt írásait nem ismeri, de valamit hallott róluk és emiatt teljesen félreérti vagy másként fogalmazva nem is érti ezeknek a lényegét.

Egyik oldal sem jobb, az sem amelyik mindent elfogad és az sem, amelyik mindent elutasít.

Ezekről az elvekről jó beszélni, mert egyrészt jobban megérthető, hogy pontosan miről is szólnak, hogyan kell és lehet ezeket alkalmazni, másrészt az ilyen elvek előnyeire és gyengeségeire is rá lehet világítani. Ehhez viszont konstruktív hozzáállás, értelmes vitakészség kellene elsősorban.

+1

Annyi sorból áll, ami az alapvető, mindig egyszerre végrehajtandó feladatot végrehajtja.
Nincs értelme egy feladatot 3 függvénybe rakni, ha utána minden esetben az a 3 függvény egymás után van meghívva, és külön-külön sosem egyik részfeladat. Csak komoly owerheadet okoz, hogy állandóan mentse a stacket....

"Csak komoly owerheadet okoz, hogy állandóan mentse a stacket...."

Ez mindig relevans szerinted?

Mi a helyzet, amikor a programozo agya a parser, probalod ertelmezni a fuggvenyt. A megoldas: meghiv 5 masik fuggvenyt, ezek neve precizen korulirja a reszfeladatot, amit megoldanak, ranezesre vili az algoritmus vaza; B megoldas: az egesz omlesztve egy nagy fuggvenybe. Melyiket konnyebb debuggolni, A-nal csak a teged erdeklo reszfeladatra nezel ra.

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

Ja, de nincs is annál jobb, mikor egy 50 soros függvényt ami komplett és kerek egész valaki kozmetikázási okok miatt elkezd szétszedegetni, majd az összetartozó kódrészletek elkezdenek elvándorolni a fájlban és a megértést egy pillanatig sem segíti elő.

Külön jó, amikor mondjuk van két egymáshoz nagyon hasonló függvényed, de pont annyi különbség van, hogy ne akarj összevonogatni belőle dolgokat és valaki mégis megteszi, aminek következtében lesz egy sokkal kötöttebb, kevésbé átláthatóbb, össze-vissza hívogató spagetti milliónyi delegálttal a külvilágból.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Izé... szép-szép a clean code, de amikor az ember szétszed egy 50 soros függvényt 3 darab 15-25 soros függvényre, hogy clean code szemüveggel "szebb" legyen, ugyanakkor ezzel az egész elveszti az áttekinthetőséget, az nem biztos, hogy jó dolog

Szívesen látnék erre példát!

Végtelen sok példa van rá... :)

Például képzeld azt, hogy egy 2D canvas-ra rajzolsz sprite-okat, a metódusod kap egy előre elkészített adatstruktúrát és az alapján kell vagy nem kell kitenned egy-egy sprite-ot. Mitől jobb az, ha ezt szétszeded három függvényre és lesz három függvényed, plusz egy, amiből meghívod ezt a három függvényt? :)

Mert ha bugot kell javitani / feature-t kell hozzaadni, akkor nem kell vegigolvasnod az egesz algoritmust, hanem ha az adatok konvertalasara vagy kivancsi, akkor azt a fuggvenyt nezed meg, ha a rajzolasra, akkor azt, stb.

A legrosszabb, amikor a kulonbozo reszfeladatok szanaszet vannak szorva a fuggvenyben, aztan talald meg, hogy az adott dolog eppen hol tortenik, ha meg egy helyre mozgatod oket, hogy a logikusan osszetartozo dolgok egy helyen legyenek, akkor siman meglepheted a +1 lepest, amivel kiszervezed oket masik metodusba.

Nem mellesleg a valtozok scope-olasara is tokeletes, hiszen nem minden adatra van szuksege egy tetszoleges reszfeladatnak, igy ha a szukseges adatot parameterkent adod at, sokkal egyszerubb megerteni a kodot, hogy vegulis mibol mi lesz vegeredmenyben. (szerk: ld: http://www.lihaoyi.com/post/WhatsFunctionalProgrammingAllAbout.html - Tiramisu Diagram to Functional Programming)

"Mert ha bugot kell javitani / feature-t kell hozzaadni, akkor nem kell vegigolvasnod az egesz algoritmust, hanem ha az adatok konvertalasara vagy kivancsi, akkor azt a fuggvenyt nezed meg, ha a rajzolasra, akkor azt, stb."

Csak rajzolás van a feltételeknek megfelelően. Hogy rövidre zárjuk, például itt van az alábbi pár sor:


Draw("1");
Draw("2");
Draw("3");
if (state1) {
Draw("4");
}
Draw("5");
Draw("6");
if (state2) {
Draw("7");
} else {
if (state1) {
Draw("8");
} else {
Draw("9");
}
}

Ebben a sorrendben kell kirajzolni a sprite-okat egymásra, a feltételeknek megfelelően. Mi alapján, hogy bontanád három részre és miért pont úgy?

Ha itt nincsenek különböző absztrakciós szintek, akkor nem jó szétvágni több részletre.

Ha vannak, akkor tegyük fel, hogy az első részben sétál a sprite, az első if azért kell bele, mert a sprite ugrik; a következő részben várakozik, a második if-nél pedig harcol (különböző fegyverekkel). Ekkor én így vágnám szét:


drawWalk();
drawJump();
drawWait();
drawFight();

Nincs korlát, ha egy absztrakciós szint van, akkor nem kell szétvágni. Épp ezt próbáljuk elmagyarázni.

Ellenben, ha nagyon sok soros és egy absztrakciós szint, akkor vélhetően refaktorálni lehet rövidebbre.

Pl.


val states = Map(
  1 -> List("1", "2", "3", "4", "5", "6", "8"),
  2 -> List("1", "2", "3", "5", "6", "7"),
  3 -> List("1", "2", "3", "5", "6", "9"))
states(state).foreach(draw(_))

"Nincs korlát, ha egy absztrakciós szint, akkor nem kell szétvágni. Épp ezt próbáljuk elmagyarázni."

Nem kell elmagyarázni, ezzel kezdtem, épp te hitetlenkedtél és kértél példát.

"Ellenben, ha nagyon sok soros és egy absztrakciós szint, akkor vélhetően refaktorálni lehet rövidebbre."

Rövidebbre vagy áttekinthetőbbre? Mi a cél?

val states = Map(
1 -> List("1", "2", "3", "4", "5", "6", "8"),
2 -> List("1", "2", "3", "5", "6", "7"),
3 -> List("1", "2", "3", "5", "6", "9"))
states(state).foreach(draw(_))

Ha van 50 state és 100 sprite, akkor is megéri rajzolni egy 50x100-as mátrixot, aminek a karbantartása egy külön kínszenvedés? Tedd fel magadnak a kérdést: minek akarsz ezzel megfelelni?

Nem kell elmagyarázni, ezzel kezdtem

Nem ezzel kezdted! Azzal kezdted, hogy amiatt kell szétvágni, hogy clean code szemüveggel "szebb" legyen.
Ha CC miatt kell szétvágni, akkor több absztrakciós szint van, ha nincs több szint, akkor nem kell!
Persicsb próbálta elmagyarázni, de ott se tanúsítottad jelét annak, hogy megértetted.

Rövidebbre vagy áttekinthetőbbre? Mi a cél?

Természetesen áttekinthetőbbre! Az utolsó példánál sokkal jobban látszik, hogy melyik állapothoz melyik sprite-ok tartoznak. Ha lenne oka, hogy miért vannak a feltételek benne (egy magasabb absztrakciós szint), akkor könnyen lehet, hogy másként lenne áttekinthetőbb, pl. mint ez példa volt:


drawWalk();
drawJump();
drawWait();
drawFight();

Csak ez akkor nem tud működni, ha nincs semmilyen logikai kapcsolat az egyes sprite-ok és egyes állapotok között, mondjuk ezt nehezen tudom elképzelni. Pl. nehéz azt elképzelni, hogy egy feltétel csak úgy ott van és nincs az meg, hogy miért (nincs egy magasabb szintű absztrakció).

Ha van 50 state és 100 sprite, akkor is megéri rajzolni egy 50x100-as mátrixot, aminek a karbantartása egy külön kínszenvedés?

Helyzete válogatja, sok esetben áttekinthetőbb és jobban karbantartható egy deklaratívan, adatszerkezettel megadott kód! Szerializálható, adatbázisban tárolható, külső programmal, GUI-val szerkeszthető, ... Vannak előnyei.

A specifikáció alapján könnyen eldönthető, hogy mi az áttekinthetőbb.

"Nem ezzel kezdted! Azzal kezdted, hogy amiatt kell szétvágni, hogy clean code szemüveggel "szebb" legyen."

Így van.

"Ha CC miatt kell szétvágni, akkor több absztrakciós szint van, ha nincs több szint, akkor nem kell!"

Akkor se kell szétvágni minden esetben, ha van. Csak ellenállhatatlan késztetést érzel rá, akkor is, ha ezzel nem lesz jobb a helyzet, csak rosszabb, sőt, beleteszel egy kockázatot is, hogy elrontod.

"Természetesen áttekinthetőbbre!"

Akkor miért lett rossz az implementációd?

"Csak ez akkor nem tud működni, ha nincs semmilyen logikai kapcsolat az egyes sprite-ok és egyes állapotok között, mondjuk ezt nehezen tudom elképzelni."

Az, hogy mit tudsz nehezen elképzelni és mi a valóság, az két külön dolog... :)

Leírtam, hogy mi a célja és mit csinál pontosan, de leírom bővebben, bár nem értem, mi köze a kérdéshez.

Van egy grafikai egységnek 10-15 állapota, aminek megfelelően ki kell tenni állapotonként egy-kettő-sok grafikai elemet köré, sokszor egy másik állapottól függő pozícióba vagy egy másik állapottól függő grafikai elemet.

Ha nagyon erősen bele akarod látni az absztrakciós szintet, mert épp CC szemüveg van rajtad, akkor szét tudod szedni 2-3 függvényre. Ha épp lean management szemüveg van rajta, akkor meg hagyod a picsába, mert muda lenne hozzányúlni.

Leírtam, hogy mi a célja és mit csinál pontosan

Még mindig nem írtad le pontosan, sőt szerintem sehogy sem. Egy olyan leírás kellene, ami alapján a programozó a fenti kódot fogja gyártani. Ezen leírások alapján én egyetlen sort se nagyon tudnék írni.

Pl. ezen leírás alapján már születhetne a fenti kód:


Hobbit kirajzolása.
- Először a hobbit sétálását rajzold ki három fázisban.
- Majd, ha van nála rugó, akkor ugorjon egyet.
- Majd várakozzon a hobbit két fázisban.
- Majd a harcolását jelenítsd meg:
  * ha van nála kés, akkor késsel
  * ha nincs, de van rugója, akkor rugóval,
  * ha az sincs, akkor ököllel

"Még mindig nem írtad le pontosan, sőt szerintem sehogy sem. Egy olyan leírás kellene, ami alapján a programozó a fenti kódot fogja gyártani. Ezen leírások alapján én egyetlen sort se nagyon tudnék írni."

Ne haragudj, de nem fogok részletes specifikációt írni.

Ilyenekről van szó:

draw(unit.getSpriteName(), 0, 0);
draw("health", index(unit.getHealthIndex()), 8, 16);

if (unit.isAutomated()) {
draw("state_automated", 16, 32);
} else if (unit.isForitfied()) {
draw("state_fortified", 16, 32);
} else if (unit.isLoaded()) {
draw("state_loaded", 16, 32);
}

if (unit.isSelected()) {
draw("grids_selection", 0, unit.getSelectionDelta());
}

Miért szedjem szét például az üres sorok mentén, ha egyben is láthatom, hogy mi, hol és mikor fog megjelenni?

No, ez már sokkal "szebb" kód, ebből már érthető, hogy mit akar csinálni, ráadásul csak két absztrakciós szintje van.

Miért szedjem szét például az üres sorok mentén, ha egyben is láthatom, hogy mi, hol és mikor fog megjelenni?

Ezt már nem feltétlen kell szétszedni, így is elfogadható.

Azonban lehet még "szebbé" tenni, aminek szintén vannak előnyei, hátrányai.


POS_SPRITE = Point(0, 0);
POS_HEALTH = Point(8, 16);
POS_STATE = Point(16, 32);

drawUnit(unit) {
  drawSprite(unit.getSpriteName());
  drawHealth(unit.getHealth());
  drawState(unit.getState());
  drawSelection(unit.getSelection());
}

drawSprite(spriteName) {
  draw(spriteName, POS_SPRITE);
}
...

Előnyei:
- olvashatóbb, könnyebben érthető kód,
- könnyebben módosítható,
- könnyebben újrafelhasználható -> kevesebb duplikáció
- jobban látható az üzleti logika,
- könnyebben optimalizálható,
- egy-egy rész kevesebb ok miatt változhat,
- nagyobb a kohéziója, kisebb az összefonódása (coupling),
...

Hátrányai:
- kicsit hosszabb,
- több idő megírni (átírni),
- ha nem tud optimalizálni raja a fordító, akkor esetleg a kisebb performancia (mérni kell!)

"Ezt már nem feltétlen kell szétszedni, így is elfogadható."

Nem "feltétlenül"? Most akkor vannak szabályok vagy rugalmas a dolog?

"Azonban lehet még "szebbé" tenni, aminek szintén vannak előnyei, hátrányai."

Ezt se sikerült hiba nélkül implementálnod, ez a kód nem azt csinálja, amit kellene... :/

Ráadásul:

"- olvashatóbb, könnyebben érthető kód,"

Szétszedted egy csomó különálló helyre azt, ami amúgy egybe tartozik.
- ha meg akarom nézni, hogy hova rajzol, akkor külön meg kell néznem, mert nincs ott a szemem előtt, ott csak egy semmitmondó konstans név van.
- ha meg akarom nézni, hogy milyen feltételek mentén rajzol, akkor külön meg kell néznem egy külön függvényben.
- ha meg akarom nézni, hogy milyen állapotok vannak, meg kell néznem a "state" értékkészletét.

"- könnyebben módosítható,"

Ha változik a "fortified" pozíciója és csak azé, akkor miért lesz könnyebben módosítható? Behoztál egy csomó plusz sort, konstanst és függvényt, amelyeket külön karban kell tartani.

"- könnyebben újrafelhasználható -> kevesebb duplikáció"

Soha nem lesz újra felhasználva, szóval nem érdekel a passzív duplikáció, hogy messziről hasonlít-e egy másik kódrészletre.

"- jobban látható az üzleti logika,"

Úgy, hogy szétszedted több helyre és nem látod egyben?

"- könnyebben optimalizálható,"

Ezzel a forrással pont optimalizációt csökkentettél, mert összevontál különálló Boolean változókat egy "state" változóba, amit aztán külön ki kell válogatni újra.

"- egy-egy rész kevesebb ok miatt változhat,"

Két éve nem változott ez a rész, ha változni fog, akkor hozzáírok egy új sort a megfelelő rétegzésbe.

"- nagyobb a kohéziója, kisebb az összefonódása (coupling),"

Oszt?

Egyébként nagyszerű példája annak, hogy mennyire káros tud lenni az erőltetett kódminőség "javítás"... elvisz egy csomó időt egy csomó látszólagos előnyért. :/

Nem "feltétlenül"? Most akkor vannak szabályok vagy rugalmas a dolog?

SLAP szerint külön kell venni, de ennek azért vannak fokozatai.
Ha egy szinten csak egy absztrakció van, akkor ott van az a rengeteg előny, amit írtam, és van egy pár hátrány. Hiába jóval olvashatóbb, karbantarthatóbb, ... a kód, ha a performancia miatt nem maradhat úgy.
Ennél kicsit rosszabb, ha két absztrakciós szint van egyben, még rosszabb, ha három, ...

Ezt se sikerült hiba nélkül implementálnod, ez a kód nem azt csinálja, amit kellene... :/

Miért nem?

Szétszedted egy csomó különálló helyre azt, ami amúgy egybe tartozik.
Úgy, hogy szétszedted több helyre és nem látod egyben?

Absztrakció: "a lényeges és lényegtelen tulajdonságok elválasztása, a lényeges tulajdonságok kiemelése és a lényegtelen tulajdonságok figyelmen kívül hagyása".

Kiemeltem az adott szinten lényeges tulajdonságokat, az azon a szinten lényegteleneket pedig egy szinttel lejjebb toltam. A unit kirajzolásakor az a lényeges, hogy mit kell kirakni, hogy pontosan hová az lényegtelen. Az is jó, hogy a pozíciók egymás mellé kerülnek, mert azok egymáshoz viszonyított helyzetük lényeges és a pozíció változtatáskor nem kell egy hosszú függvényben konstansokat cserélnem. Utóbbi esetben sokkal nagyobb az esélye, hogy hibát vétesz.

Ha változik a "fortified" pozíciója és csak azé, akkor miért lesz könnyebben módosítható?

Ha változik és csak azé változik, akkor kell egy új POS_STATE_FORTIFIED és a rövid drawState-ben kell kicserélni az adott sornál a POS_STATE-et erre az újra.

Változhat még ezer minden, pl. ha:
- változik bármelyik meglévő pozíciója, akkor csak a pozíciós konstansánál kell kicserélnem az értéket, könnyen megtalálom, kicsi az esély a hibára;
- új állapotot kell kirajzolni, akkor csak a drawState-et kell módosítani;
- változik a sprite kirajzolása, akkor csak a drawSprite-ot kell változtatni;
- új elemet kell a unithoz megjeleníteni, akkor csak a drawUnit változik és lesz egy új rövid rajzoló az új elemhez.

Minden esetben csak egy kis részt érint a változás, sokkal kisebb a hibázási lehetőség, sokkal kevesebbet kell az esetleges unit teszteken változtatni.

Ezzel a forrással pont optimalizációt csökkentettél

Hogyan valósítanád meg a saját kódoddal, hogy az egyes unit elemek kirajzolása egymással párhuzamosan történjen?
Hogyan valósítanád meg a saját kódoddal, hogy bizonyos feltételek esetén más sorrendben fussanak le az egyes unit elemek kirajzolásai?

Egyébként nagyszerű példája annak, hogy mennyire káros tud lenni az erőltetett kódminőség "javítás"... elvisz egy csomó időt egy csomó látszólagos előnyért.

Szerintem nem látszólagosak az előnyök!
Nem akarlak se Téged, se mást meggyőzni!
Örülök, hogy újra képbe került a kódminőség és egy kicsit tudtunk a témában gondolatokat cserélni.
Remélem azért lesznek olyanok, akik tudnak ebből profitálni a későbbi munkájuk során!

"SLAP szerint külön kell venni, de ennek azért vannak fokozatai."

Aha. Szóval már fokozatoknál tartunk... egyre igazabb lesz a nyitó állításom.

"Miért nem?"

Mert nem, keresd meg a hibádat. Se ezt nem sikerült jól implementálnod, se a map alapú megoldást. Kezdem azt hinni, hogy nem tudsz szépen és jól kódolni.

"A unit kirajzolásakor az a lényeges, hogy mit kell kirakni, hogy pontosan hová az lényegtelen."

Nem lényegtelen, hanem lényeges része a kirajzolásnak, hogy _mit_, _mikor_ és _hova_ rajzolok... ez a három dolog együtt határozza meg a végeredményt.

"Ha változik és csak azé változik, akkor kell egy új POS_STATE_FORTIFIED és a rövid drawState-ben kell kicserélni az adott sornál a POS_STATE-et erre az újra."

A másik megoldásban meg két számot kell megváltoztatni...

"Minden esetben csak egy kis részt érint a változás, sokkal kisebb a hibázási lehetőség, sokkal kevesebbet kell az esetleges unit teszteken változtatni."

Nézzük mondjuk azt, amikor az automated unit is lehet fortified állapotban. Akkor mennyi helyen kell módosítanod?

"Hogyan valósítanád meg a saját kódoddal, hogy az egyes unit elemek kirajzolása egymással párhuzamosan történjen? Hogyan valósítanád meg a saját kódoddal, hogy bizonyos feltételek esetén más sorrendben fussanak le az egyes unit elemek kirajzolásai?"

Egymásra rétegezett sprite-ok esetén ezek nem fordulhatnak elő, nem kell rá felkészülni.

"Szerintem nem látszólagosak az előnyök!"

Hát... ha fejlesztettél 2D OpenGL alkalmazást, akkor rájönnél, hogy látszólagosak.

"Nem akarlak se Téged, se mást meggyőzni!"

Aha... nem.

CC. Aki pedig nem tudja szétszedni a hosszú dolgokat vagy hülyeségnek tartja, annak el kell megint olvasnia a könyvet.

csak férjen ki a 384/2 leporellóra.

Ez megint egy vallási kérdés, amire a lehetséges válaszok közül megint hiányzik az "attól függ..." opció.
Egy függvény akkor megfelelő hosszúságú, ha ellátja a feladatát, és csak a feladatát.

Bár jómagam scriptelek, és nem programozok, ami talán más szemléletet jelenthet,
de nálam az a szempont, hogy ha egy részfeladat ismétlődik, akkor az függvénybe megy.
Így akad több mint 100 soros függvényem is, meg egysoros is. Mindegyik megfelelő hosszúságú. :)

---
"A megoldásra kell koncentrálni nem a problémára."

Ezek a dolgok egyébként erősen összefüggnek. Ha bonyolult a tesztelendő függvényed, akkor bonyolult lesz a tesztje is. Ha egyszerűsítesz a függvényeden (pl. több függvényre bontod), akkor egyszerűbb lesz a teszted is.

A unit teszt sem kell, hogy egyetlen függvényből álljon, pl.:


@Test testAnything() {
  cds = createComplexDataStructure(...);
  assertEquals(anything(cds), 15);
}

createComplexDataStructure(...) {
  ...
}

Miért ne tudnám, hiszen szépen el van nevezve?
Ráadásul egy mozdulattal bele is tudok ugrani, ha részletesen tudni akarom miként áll elő a komplex adatstruktúra.
A tesztesetnél bőven elég annyi, amennyi az adott szint megértéséhez elég. Ha mélyebben meg akarom egy részét érteni, akkor belemegyek az adott részbe.
A teszt kód az ugyanolyan kód, mint a program kódja. Pontosan ugyanúgy kell tervezni, módosítani, megérteni, ...
és ugyanúgy lesznek benne hibák is. Emiatt ugyanolyan jól tervezettre, karbantarthatóra, olvashatóra, ... kell csinálni, mint a rendes kódot.
Ráadásul, ha sok kicsi függvényed van, akkor sok kicsi teszted is lesz és ilyenkor fel se nagyon merül, hogy szétszabdald a teszteket.

Ha a unit tesztedet kulonbozo fuggvenyhivasokkal kell olvashatobba tenni, az azt jelenti, hogy a fuggvenyed tul sok dolgot akar csinalni egyszerre. Erre _nem_ az a megoldas, hogy elrejtjuk a teszt komplexitasat, hanem az, hogy az adott fuggvenyt tovabb bontjuk, amely reszfeladatokat mar egyszerubb tesztelni.

Unit tesztet _nem_ ugyanazokkal a technikakkal kell kesziteni, mint programot. A tesztnek konnyen atlathatonak kell lennie mindenfele ugrabugra nelkul.

Itt zavart érzek az erőben! :-)

A tesztnek konnyen atlathatonak kell lennie mindenfele ugrabugra nelkul.

Pontosan, ahogy a program kódnak is!
Mit is írtál, hogyan teszed egyszerűbbé az adott (komplex) függvényt, amit tesztelni akarsz?

az adott fuggvenyt tovabb bontjuk

Pontosan! Ahogy egyszerűbb lesz a függvényed a szétbontással, úgy egyszerűbb lesz a teszt kódod is a szétbontással, nem komplikáltabb!

Ha a production kod szet van bontva, akkor a teszteket nem kell bontogatni, mert azok is csak par sorosak lesznek a mockok felsetupolasaval, asszertacioval egyutt.

Viszont ha ugy nez ki egy unit test, hogy


void test() {
  setUpMocksForXYTest();
  performTest();
  performAssertion();
}

az nem jo, mert ebben az esetben ugyan olvashato a kod, de a tesztkomplexitas el van rejtve egy masik szint ala. Ha ugy irod, hogy


void test() {
  // GIVEN
  ... lets setup the mocks/stubs/whateva ...

  // WHEN
  ... lets perform the test ...

  // THEN
  ... assert the result ...
}

akkor maris sikerult strukturalnod a unit tesztet az olvashatosag miatt, viszont mivel nem rejted el a komplexitast, igy ha a teszted mar szar karbantartani, akkor tudod, hogy valami buzlik a prod. kodban.

Az elso pelda tokeletes lehet BDD-re, ahol kulonbozo state-ket kell letrehozni/felsetupolni az integracios/end-to-end tesztekhez.

Szerintem elbeszélünk egymás mellett. Nem ilyen szétbontásról beszélek.

A performTest, performAssertion az egy (pár) sor kellene legyen egy normális unit testben, tehát teljesen rossz ötlet külön függvénybe rakni.

A setUpMocksForXYTest rész szétbontásáról beszélek, ha az adott tesztnél több absztrakciós szintet is képvisel.
Én a mockot nem tartom jónak, így inkább kicsit más példát adnék:


StringBuilder sb = new StringBuilder("{")
  .append("'id':")
  .append('fe15-ac78')
  .append(", 'name': ")
  .append("'Teszt Elek'")
...
  .append("}");

String jsonUser = sb.toString();

vs.


  String id = "fe15-ac78";
  String name = "Teszt Elek";
  ...
  String jsonUser = createJsonUser(id, name, ...);

A createJsonUser csinálhatja a teszt szempontjából teljesen lényegtelen Json szerializációt, kb. mint ami a fenti esetben is van.

Technikailag nyilván lehetne. De minek?
Logikailag ott a helye, sehol máshol nem használok semmit ami benne van, csak ott.
Miért szabdaljam??? Az egész script 700 sor...

Mint fentebb jeleztem, scripteket írok (leginkább perl-ben de ez most mindegy), és mint olyan ezek jellemzően egy file-os, 3-1000 sor hosszúak.
Nem bonyolult programrendszerek...
Sőt néha ad-hoc termékek egy-egy célfeladatra, ahol a szépség végképp nem számít. ;)

---
"A megoldásra kell koncentrálni nem a problémára."

+1

Pont ezt akartam irni en is.

(Peterson 6:01 -es hozzaszolasara akart valasz lenni)

A "ferjen ki a kepernyore" vezet?

Meg szerencse, hogy jo a szemem es lejjebb tudom venni meg eggyel a betumeretet :P

nem tudom ki találta ki ezt a fájl minimapet de áldassék a neve. Ma már mindegy mekkora egy fájl vagy függvény.

--
GPLv3-as hozzászólás.

Az is mindegy lehetne már, hogy mi a fájl. Különösen idegesítő, mikor egyébként is az a policy, hogy a névtereknek, osztályoknak 1-1 relációban kell lennie a fájljokkal, könyvtárakkal és ezt kézzel kell karbantartani.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Jó, nem mondom, hogy itt nincs (vagy nem lehet) benne pluszban a céges policy is, de igazából meghaladottnak érzem már ezt a fájlokkal való baszakodást.

Sok esetben azt látom, hogy csupán azért csinálunk dolgokat, mert bizonyos funkciók különálló, részben gyengébb toolokban vannak, ahelyett, hogy egy integrált környezetben lenne megoldva. Konkrét példa erre pl. házon belül a review folyamat: sokszor VS-ben tök triviális lenne valamiben a navigáció, vagy áttekinteni valamit, de muszáj máshogy csinálni, különben a TFS-ben nem fogja érteni a reviewon senki. Pedig semmi szükség nem lenne erre, ha a VS-ben lenne a review funkció vagy a TFS is rendelkezne azzal a navigációs képességgel, mint a VS. Stb.

Van előnye is annak, hogy a dolgok képesek együttműködni.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

(sub)

-------
It is our choices that define us.

Ezek a vallasos dogmak azoknak kellenek, akik nem tudjak megitelni, hogy milyen esetben milyen hosszu lehet egy fuggveny es mi tartozik logikailag egy szubrutinba. Szamomra teljesen elvetemult dolog kodrol beszelni design nelkul, raadasul a kodot egyetlen meroszam alapjan megitelni.

Ezek a vallásos dogmák (elvek) épp arról szólnak, hogyan ítéljük meg, hogy milyen esetben milyen hosszu lehet egy fuggveny es mi tartozik logikailag egy szubrutinba.

Ha design-ról beszélsz, akkor valami alapján Te is megítéled ezeket a dolgokat. Te mi alapján ítéled meg? Miért gondolod rossznak a SLAP elvet?

A dogmak semmiben sem segitenek, csak kikapcsoljak a gondolkodast.

Nem lehet szeirntem egy elv menten a fuggvenyek mereterol es tartlmarol dontest hozni. Pont arrol beszelek, hogy ebben tobb faktor jatszik szerepet. En jellemzoen logikailag osszetartozo tevekenysegeket szoktam egy fuggvenybe szervezni (egy fuggvenynek jol meghatorzott, jol korulirhato, nevesitheto feladata van), de vannak mas elvek is. Pl. tipikusan alkalmazok vezerlo es vegrehajto fuggvenyeket. Az absztrakcios szintek atlepeset ugyan kereulom, de nem szabad elfelejteni, hogy az absztrakcios szint is csak definicio kerdese es erosen kontextus fuggo. Az is persze erdekes kerdes, hogy vajon milyen tervezesrol arulkodik az az osztaly, amelyben sok valodi absztrakcios szint van jelen.

Az SLA onmagabn nem egy hibas elv, de vakbuzgo kovetesenel tipikus hibakent eloallhat az ertelmetlen metodus szaporitas illetve az indokolatlanul mely call stack, ami semmivel nem eredmenyez atlathatobb kodot, mint ha egy fuggveny nehany sorral hosszabb. Raadasul a call stacknek beagyazott rendszereken igenis jelentosege van teljesitmeny szempontjabol.

Nincs szent gral, gondolkodni kell, es nem csak kod szinten, hanem a teljes hardver es szoftver architektura es design szinten.

Ezek nem dogmák, hanem elvek. Akkor lesz egy elv dogma, ha valaki eszetlenül használja. Ez az egyik véglet, a másik meg az, ha nem is tud róla, nem tudja mire való, mikor jó, mikor nem.

Ha sokan nem használják, vagy rosszul használják az nem azt jelenti, hogy rossz az elv.

En jellemzoen logikailag osszetartozo tevekenysegeket szoktam egy fuggvenybe szervezni

Ez kb. az összes függvényre igaz, elég csak a main függvényre gondolni. A lényeg pont azon van, hogy miként és milyen mértékben bontod részekre.

Az is persze erdekes kerdes, hogy vajon milyen tervezesrol arulkodik az az osztaly, amelyben sok valodi absztrakcios szint van jelen.

Ezt a "valódi absztrakciós szint" kifejezést nem igazán értem. Az absztrakció az pont egy elvi dolog.

Absztrakció: a lényeges és lényegtelen tulajdonságok elválasztása, a lényeges tulajdonságok kiemelése és a lényegtelen tulajdonságok figyelmen kívül hagyása.

Pl. rendelés módosítása. Ez a legfelső absztrakciós szint, pl. így bontjuk tovább:
1. Bemenet értelmezése
2. Módosítás elvégzése
3. Eredmény visszaadása

Ezeket bonthatjuk tovább, pl.
1.1 Bejövő string json struktúrává alakítása
1.2 Json struktúra átalakítása domain osztály struktúrává
...

Raadasul a call stacknek beagyazott rendszereken igenis jelentosege van teljesitmeny szempontjabol.

Régen lehet, hogy volt, de ma már a fordítók ezt megoldják automatikusan vagy segítséggel (pl. inline).

Most vegulis min vitatkozol velem?

En irtam: "Az SLA onmagabn nem egy hibas elv, de vakbuzgo kovetesenel tipikus hibakent ...."

Te irtad: "Ezek nem dogmák, hanem elvek. Akkor lesz egy elv dogma, ha valaki eszetlenül használja. Ez az egyik véglet, a másik meg az, ha nem is tud róla, nem tudja mire való, mikor jó, mikor nem."

Lenyegebn ugyanazt irtad.

Az absztrakciorol:
A valodi absztrakcios szint az, aminek ertelme is van az adott kontextusban. Eroltetten persze nagyon sok szint bevezetheto. Amire en az egy osztalyon belul implementalt valodi absztrakcios szintekkkel utalni akartam, az a te altalad hozott peldadbol is kezd kirajzolodni: jo esellyel a json vagy egyeb bemenet parser mar egy masik osztalyban / retegben talalhat helyet. Nyilvan nem kotelezeo, de van ra esely.

Call stack: "Régen lehet, hogy volt, de ma már a fordítók ezt megoldják automatikusan vagy segítséggel (pl. inline)."

Kerlek a katalogus muveltseget hagyjuk, ez a valosagban nem igy van.

Általában férjen ki a képernyőre, de ha meg lehet magyarázni, akkor lehet nagyobb is.

... hát, az attól függ, mit kell csinálnia a függvénynek. Néhány utasítás miatt meg nem szeretek függvényt írni, mert futáskor a függvényhívás lehet, hogy hosszabb ideig tartana, mint az a néhány sor végrehajtása.

-fs-
Az olyan tárgyakat, amik képesek az mc futtatására, munkaeszköznek nevezzük.
/usr/lib/libasound.so --gágágágá --lilaliba

Megosztom, mert tudom ezzel nem vagyok egyedül:
Amikor életemben először értettem meg a CC-t, akkor kurvára elszégyelltem magam és elég borúsan láttam az addigi munkáimat. Azt éreztem, hogy egy kókler vagyok.

Ugyan. Nem szégyen ez. Rendkívül kevés ember van, aki egy szakmában tanítás meg orbitális szívás nélkül egyből zsigerből tudja, hogy mi a jó. Ahogy szokták mondani, tehetséges az, aki többet tud, mint amit tanult.

Illetve ha egy szakmában nem tanítják meg, hogy miként kell jól/jobban csinálni, nem kell elvárni senkitől, hogy tudja önmagától.

Az inkább elszomorító, hogy az adófizetők pénzéből szándékosan erre a célra fenntartott oktatási intézmények nem oktatják ezt. Az ő dolguk lenne.

Amikor rácsodálkozik az ember arra, hogy milyen keveset tud, mert még keveset tanult, akkor nem szégyen érzet kell, hogy eltöltse szerintem, hanem szerénység, meg az a fajta "gyermeki" rácsodálkozás, amikor rájön az ember, hogy a világ sokkal több, mint amit addig látott belőle. És ez baromi jó érzés. Egy kicsit olyan, mint a felfedezés öröme.

"Az inkább elszomorító"

A még inkább, amikor ez azzal társul, hogy ő a valaki, mert elvégezte az OKJ-t, egyetemet, miegyebet, aztán ott van 0 km-es tapasztalattal, majd mikor mondod neki, hogy ez remek, de gyakorlatban ez-az-amaz így meg úgy működik, akkor megsértődik és szerinte az elvárásokkal van a probléma.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Btw akármekkora flamelések vannak a threadekben, de talán személyeskedés annyira még nem volt, és valahogy ezt a szavazást jobban a HUP profiljába illőnek érzem, mint a "van macskád" vagy éppen a "hol eszel munkaidő alatt" szavazásokat és beszélgetéseket.
Szóval denesb, köszi, hogy beküldted ezt a szavazást.