Geri blogja

Tisztelt látogató!
Ez a blog 2017 óta átmenetileg szünetel!

Friss topikok

Bejegyzések

Mi a baj az objektumorientált programozással?

2016.12.23. 12:48 Gerilgfx

Az objektumorientált programozás lényege az, hogy a programozást nem a számítógép szemszögéből közelítjük meg, hanem a problémát objektumokká bontjuk, amelyeknek a viselkedését implementáljuk. Az objektumorientáltság a programozási nyelvek esetében nem konkrétan egy gondolkodásmódot jelent, hanem azt, hogy ennek megvalósítása céljából nyelvi elemek állnak rendelkezésre, amelyek révén a program elkészíthető. 

Az objektumorientált programozási nyelvek osztályokká és példányokká szabdalják a problémát. Tehát ha mondjuk valaki egy mozdony vezérlését egy objektumorientált nyelvben írja meg, akkor lesz egy osztály maga a vonat. A vonat osztályon belül lesz a mozdony osztálya, és lesz a kocsik osztálya. Lesz egy osztály a kerekeknek. Lesz egy példány a mozdonyból, mondjuk 5 példány a kocsikból, és mind a kocsik, mind a mozdony esetében lesz mondjuk 16 - vagy mittudomén hány - példány a kerékből.

A különböző osztályok nem csak a levegőben lógnak, hanem egymás részei lehetnek, amelyek interakcióba léphetnek egymással, tehát ha mondjuk elindul az adott kocsi - valamelyik kerék forgatását jelző függvény meghívódik - akkor ezt ilyen-olyan hackek segítségével az ajtó példányai is érzékelni tudják, és így az ajtó autómatikusan becsukódhat.

 

1. probléma: Az objektumorientált programozás pont, hogy a valóságot nem képes objektumokká képezni, tehát már arra sem jó, amire kitalálták

Mi történik akkor, ha a vonat lefékez? A folyamat a szerelvény egészére hat, de a mozdony logikailag a kocsikkal kb egy szinten van, mégis ki kell hatnia minden kocsira, a kerekekre, és a szerelvény egészére, tehát minden irányban. Ugyanez igaz arra, amikor valaki behúzza a vészféket. Látható, hogy a tárgyak interakciója sokrétűbb annál, hogy ezt halmaz-részhalmaz szerű logika alapján kapcsolatokká lehessen szervezni, így az egész koncepció megerőszakolása, és undorítóan ordas nagy hackek kellenek ahhoz, hogy osztályokká és objektumokká lehessen erőszakolni a feladatot.

 

2. A gépigény

Nem nehéz belátni, hogy ha objektumok láncolatává szerveztél valamit, amelyek egymással interakcióban vannak, akkor az horribilisen nagy overheadet tud jelenteni a gépigény tekintetében. Például ha csináltál egy vektor osztályt, amely autómatikusan kiszámítja a vektor normálvektorát és hosszát, az pont tizedelni fogja az algoritmus sebességét, lehet, hogy feleslegesen, mert neked a normálvektora mondjuk csak az egész kódban 2 helyen kell, de mondjuk a vektor iránya több ezer helyen, sebességkritikus részeken. A megoldás kézenfekvő: nem kell mindig kiszámolni a normálvektort, csak ha szűkséges. Tehát létrehoztál egy objektumot, amely vagy nem fog objektumként viselkedni többé, vagy 50 fps helyett lesz 5 fps a játékod...

 

3. A munkamorál

A sok különböző osztályt egyszerűen szét lehet bontani fájlokra, egy nagyvállalat számára tehát ez akár még egy ideális szervezőerő is lehet. Minden osztály és objektum fejlesztését le lehet osztani a különböző kollegákra. Persze ezt OOP nélkül is meg lehet tenni. OOP-vel viszont lehet úgy dolgozni, hogy nem dolgozol. Gépelgeted az osztályokat, akár több ezret is létrehozol belőle, gyönyörűen osztályokká bontottál egy egész problémát, hónapok alatt azon dolgoztál, hogy mondjuk egy csomagküldőszolgálat működését hogyan objektumizáld. Majd amikor valaki megkérdezi, hogy hol tartasz, már büffentheted is neki oda, hogy nézd már, mennyi kód van, amely megyénként osztályba szervezi a futárokat, a járműveiket, a javíttatásukat, a megrendelőket, az ügyfeleket, a grafikus felület vezérlését, a loginrendszert. Tulajdonképpen már majdnem minden kész van, csak még egyvalamit nem kezdtél el megcsinálni: a programot, amit ennyi idő alatt akár meg is írhattál volna. Hisz akár egy 7. osztályos diák is megírta volna basicben házi feladatként egy hétvége alatt, de neked mostmár 10 alkalmazott is kelleni fog hozzá, meg egy jó fél év, hogy legyen is belőle valami, aztán kvadozás után a tábortűznél lehet róla anekdotázni, hogy te mekkora fejlesztőzsuga vagy, nagyon komoly munkát végzel egy nagyon komoly nagyvállalatnál a többi 10 idiótával együtt, akik ideológiailag bevédik egymás seggét azt az impressziót keltve, hogy tulajdonképpen dolgoznak akkor, amikor valaki megkérdezi, hogy tulajdonképpen mi a kurva anyátokat is csináltok ti itt? Önmagában persze az objektumorienált programozás még nem feltétlenül kéne, hogy tönkretegyen egy projektet, hisz ha így lenne, akkor kihalt volna az egész. De a programozást mégis általában produktivitás nélküli tevékenységgé silányítja, ami utat nyitva az áltudományos megszakértgetés felé a költségek végére 2-3 nullát ír. Érdekes módon aztán a komoly munkákban, vagy az adott szoftver komoly részeiben objektumorientált programozásnak aztán nyoma sincs. 

 

4. Tehát lehetne jól is használni az objektumorientált programozást, de az emberek mégsem jól használják.

Régebben néha előfordult, hogy ha volt egy olyan ismerősöm, aki valamihez jobban ért, mint én, akkor megkértem, hogy írja meg helyettem ezt-azt a problémát, cserébe mondjuk segítettem neki a hibákat javítani, vagy tesztelni segítettem, esetleg tanácsokkal szolgáltam neki az ilyen-olyan dolgok implementálásához. Ezek mindig egyszerű problémák voltak, de előfordult, hogy ezek az emberek objektumorientált kódot adtak és a néhány órás munka helyett hetekig kotlottak rajta, hogy a végén sík ideg arccal odaadják, hogy tessék, itt van a szarod. Hát mondom, ember, mi történt? Nézem a kódot, és az érdemi része kb 300 sor. A körülötte lévő objektumgyűrű pedig 4000, és minden 3.-4. meghívás után segfaultol a program. Ez nem túlzás, és nem vicc, ez egy fájlformátum betöltője volt, amely annyit csinált, hogy a chunkok alapján fseekelt, és betöltötte az adatokat. A kód pár száz kilobájtos fájlokon 3-4 másodpercig dolgozott, az eredményeket kb olyan szintaktikával kellett kiszedni, hogy object->loader->vtx->chunk1.data.xyz(id).xyz1[k] és annyira bugos volt, hogy egy idő után inkább egyszerűen megírtam C-ben, ami 2 órát emésztett fel az életemből, és lett 300-400 sor, a működése pedig szám szerint 200x lett gyorsabb. Az emberek 99%-a tehát ótvar szarul használja az OOP-t, tulajdonképpen általában minnél inkább vergődik valaki az OOP elvek mellett, annál inkább nem érti, meg annál inkább nem tudja használni, meg annál inkább nem tud programozni.

 

5. Az objektumorientált programozás célja a kód átláthatóságának és egyszerűségének növelése lenne

ooop.pngMi a halál bágyadt fasza ez?

 

És ez az, amire az OOP képtelen. Ennek ellenére ma már az objektumorientált programozást lehetévő tevő, vagy ennek kizárólagosságát hirdető nyelvek vannak többségben, mert egész egyszerűen a nagyvállalati kóklerprogramozók ebben szeretnének dolgokat megszakértgetni bármiféle valódi munka, hozzáértés, vagy tudás nélkül, és azt akarják, hogy őket a valódi programozók a munkájukkal eltartsák - miközben ők pedig a program felesleges, obskúrus rétegeinek megszakértésével büffentgetnek, majd egymás pozícióba szopkodása után gargalizálnak.

Összességében tehát objektumorientált kódot manapság olyan projekteknél használnak, ahol nincs hozzáértő ember, ahol nincs szűkség valódi programozási munkára, ahol feltétel az, hogy a projekt SOHA SE készüljön el, drága legyen, lassú legyen, az indokoltnál tízszer több ember kelljen hozzá, tízszer akkora legyen, mint indokolt, sokáig tartson elkészíteni, ne legyen átlátható, ne legyen érdemben továbbfejleszthető, sokat lehessen kérni érte, miközben a programozói munkát igénylő feladatok esetén (pl linux kernel, titkosítóalgoritmusok, stb) mindenkit azonnal kivágnak, aki oop kódot próbál beleszakérteni a forrásba, ugyanis van, ahol egy programozói munkát tényleg programozóknak kell elvégezni.

Az OOP tulajdonképpen a szoftverfejlesztés liberalizmusa, és azt üzeni, hogy nem kell érteni semmihez, elég, ha írsz egy ügyes osztályt, és akár még megszakértő manager is lehet belőled egy nagyon komoly európai nagyvállalat pincéjében. Persze OOP-s nyelvekben is vannak jó programozók, akik ténylegesen is dolgoznak, csak mondjuk relatíve elég kevés, míg a C-sek közül általában a negyede képes rendes munkát végezni, addig az OOP-s nyelvekben ez az arány 1% sincs.

 

 

A bejegyzés trackback címe:

https://gerilgfx.blog.hu/api/trackback/id/tr6212069455

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

tamareaf 2017.05.15. 01:44:41

Tisztelt gerilgfx, a számos hiba közül, ami a bejegyzésben van, hadd emeljem ki a teljesen hibás vektoros példát.

A példának semmi értelme nincs. Objektum orientált programozás elsősorban az adat és a hozzájuk tartozó metódusok egységbe zárásáról szól, reprezentációról szó sincs.

A vektoros példa esetén, az objektum nem köteles a vektor hosszát állandóan fejben tartani, elég, ha akkor számolja ki ha arra szükség van. S persze a kettő között még van egy-kettő opció.

Ezenkívül nem mennék bele, hogy az objektum orientáltság egy tág fogalom. Mivel Önnek az írása alapján hiányzik a tágabb tudása a programozási paradigmákról, tanácsolnám hogy olvasson utána milyen nagy különbségek vannak e módszernek az implementálásába a különböző nyelvekben.

Gerilgfx 2017.05.15. 04:57:06

@feamatar: kedves feamatar, a hozzászólásban leírtakra ott van a magyarázat cikkben minden esetben, például konkrétan a vektoros példával kapcsolatban leírtakra is elég nyilvánvalóan le van írva - még az is, hogy csak akkor kell kiszámolni, ha szűkség van rá, méghozzá szinte ugyanazokat a szavakat használva, mint a hozzászólásban. Így aztán nem tudom mire vélni a hozzászólást.

Illetve dehogynem, tisztában vagyok vele, hogy ez már-már szinte egy átideologizált téma sokaknak, és ezért vigyázni is kell azzal, hogyan nyújtjuk-alakítjuk a fogalom határait, mint ahogy ez a politikában így van: ,,uraim, önök addig mennek jobbra, amíg megérkeznek balra''.

tamareaf 2017.05.15. 11:22:29

@Gerilgfx: "Tehát létrehoztál egy objektumot, amely vagy nem fog objektumként viselkedni többé, " -> ez az allitas ami nem igaz. Az ugyanis, hogy egy vektor objektum eltarolja a hosszat, vagy biztosit egy fuggvenyt ami kiszamolja, netan cacheli az erteket az implementacios kerdes, nincs koze ay objektum-orientalt paradigmahoz.

Gerilgfx 2017.05.15. 15:48:56

@feamatar: az ember azért fejleszt, hogy implementáljon valamit. ez egy egyszerű példa, ahol a paradigma követése már kizárólag rossz alternatívákat eredményez.

1. a hosszot kiszámolni mindig nyilvánvalóan rossz megoldás, mert hasztalanul elégeti a sebességet. ebben egyet is értünk, a cikk is felhívja rá a figyelmet - csakhogy az objektumorientált ezt követelné meg, és nem pedig azt, hogy külön függvényt írj rá.

2. a hosszát kiszámolni a classba helyezett függvény segítségével pedig nem más, mint csendes elismerése annak, hogy csak procedurális megoldással lehet ezt a problémát rendesen megoldani. csak épp a vektor pointere helyett a compiler az objektum pointerét zsonglőrködi át, de maga a problémára már effektíve egy procedurális megoldás született. a helyzet problematikája akkor fog kicsúcsosodni, ha folytatod a kódot: az oop itt annyit tett, hogy a koncepciójára hivatkozva egy függvényt az adatok mellé implementáltatott, tehát ezt a függvényt innentől kezdve lehet átmásolni vagy több objektumhoz, vagy öröklés útján lehet összehackelni egymással az esetlegesen össze sem illő osztályokat CSAK azért, hogy ezeket a függvényeket (amelyek csak ideológiai okok miatt lettek classek részeivé) máshonnan is el lehessen érni.
az oop lényege a valódi világ leképezése lenne, amelyet ezen a példán el is bukik, hisz csak hagyományos megoldások koncepcióba erőszakolásával lehet bármiféle eredményt elérni, de mindenféleképpen sokkal roszabb az eredmény (vagy lasabb kódot csinál, és/vagy kényelmetlenebb használni, és/vagy sokkal tovább tart csinálni, és/vagy sokkal hoszabb kódot eredményez bármiféle előny nélkül).

tamareaf 2017.05.15. 17:54:04

@Gerilgfx: Javasolnam olvass kicsit OOProl, mielott irni kezdesz rola.

"a hosszát kiszámolni a classba helyezett függvény segítségével pedig nem más, mint csendes elismerése annak, hogy csak procedurális megoldással lehet ezt a problémát rendesen megoldani. csak épp a vektor pointere helyett a compiler az objektum pointerét zsonglőrködi át, de maga a problémára már effektíve egy procedurális megoldás született. " - Amit leirsz az az OOP egyik alapeleme, az encapsulation. Az adatot és a hozza tartozo fuggvenyeket egysegbe zarjuk. Az, hogy ez gepi kodra hogy fordul az mellekes.

Itt van egy alapozo C++ tutorial, hogy megertsd:
www.cplusplus.com/doc/tutorial/classes/

Vagy a vektoros peldad C++ illetve Java nyelven:
github.com/TTimo/doom3.gpl/blob/master/neo/idlib/math/Vector.h
github.com/jMonkeyEngine/jmonkeyengine/blob/master/jme3-core/src/main/java/com/jme3/math/Vector3f.java

Gerilgfx 2017.05.15. 18:01:37

@feamatar: köszönöm, de dolgoztam már több alkalommal oop-vel, nem azért, mert úgy akartam, hanem mert muszáj volt (és korábban pedig 5-ösre vizsgáztam c++-ból, mert az is muszáj volt). ennyi nekem épp elég volt ahhoz, hogy véglegesen ítéletet mondhassak felette, és a piac is ítéletet mondott felette akkor, amikor a cpp népszerűsége üstökösként kezdett lehuzanni (pl tiobe index). hamarosan holt nyelv lesz.

tamareaf 2017.05.16. 00:09:23

@Gerilgfx: Válaszod első mondata még az OOPre vonatkozik, míg a második már a C++ra. Ezt így nem feltétlen tudom értelmezni.

Javaslom maradjunk az OOP kritikájánál, hisz arról szól a bejegyzésed, nem a C++ kritikájáról.

Én mellékeltem 3 linket, amik demonstrálják, hogy OOP nem jelenti azt, hogy egy objektumon minden attribútumként lenne tárolva. Te esetleg alá tudnád támasztani valamivel az állításod?

Érdekelne például mi a forrásod az egységbe zárásra, mert a te értelmezésedet én még soha nem hallottam.

Gerilgfx 2017.05.16. 01:08:35

@feamatar: tudom, hogy a java most a legnépszerűbb oop-s nyelv, de mivel azt nem ismerem (sosem használtam, és nem is tervezem használni), így arról nem tudok nyilatkozni semmilyen formában, ezért emeltem ki a c++-t (ha már azzal kapcsolatban is linkeltél).

az egységbe zárást tekintve maradhatunk a wikipedia definíciójánál (isten ments, hogy újakat akarjak kitalálni helyette). nézd meg alaposan az általad linkelt cpp forrást az állításaidra - sőt, legyen ez a forrás az én állításaimra is, vegyük úgy, hogy ez a vektorok oop kezelését ügyesen bemutatja minden szemszögből.

-van három féle kiszámítás a vektor hosszára (vagy legalábbis én annyi félét látok), aztán mégegyszer majdnem ugyanez 3d-ben. ezek objektumokba vannak bugyolálva. maga az a tény, hogy oop-t használtál, és a koordinátákhoz nem egy egyszerű pointert, meghosszabbította, és elbonyolította a kódot, növelte a bonyolultsági fokát feleslegesen. nyilván azért van háromszor implementálva, hogy ahol lehet, kihagyják a gyökvonást. ez a számítógép szintjén dolgozva nagyban gyorsítja a működést, csak ezzel a procerudális nyelvek hardverközeli gondolkodásához próbáltál lenyúlni olyan módon, hogy az egész egy olyan objektumbugyiban van benne, amivel már feleslegesen elégeted az órajeleket, és feltoltad a bonyolultságot.

-ráadásul a dolgok a header fájlban vannak implementálva (elég nagy gányolás, ráadásul így a bináris kódjuk többszörösen beszúródik)

-mindenféle logika mentén eltárolt értékekhez külön-külön függvények vannak implementálva feleslegesen, kizárólag azért, mert OOP koncepcióba kellett kényszeríteni az egész kódot (van, ahol a saját adattípusát, van, ahol sima floatot használ a műveletekhez). Később aztán az idvec2 mellé behoz mégegy idvec3-mat, ami ugyanez, csak 3 dimenzióban, és az egyikből áthozni a másikba az adatot szexuális kifejezéssel élve a seggből szájba tipikus esete

-az egész koncepció kényszeredetten objektumosít, mindenféle kétbetűs butaság kedvéért külön függvényt kell implementálni (pl skalár szorzat), és ha épp az adatot valahogy máshol/máshogy tároltad le, akkor hozhatod össze az egészet

-ebben a kódban látszik, hogy a készítők mindent attribútumokká gyúrtak, amit csak bírtak, ezt épp te bizonyítod ezzel az examplevel, úgyhogy én már nem is törném magam, hogy más linkeket keressek hasonló kódra (gyaníthatóan majdnem mind ilyesmi lenne). persze megengedhetjük - és miért ne tehetnénk - főleg, ha még a nyelv is megengedi (a c++ megengedi), hogy ne legyen attribútum az, ami oda nem annyira való. ha te azt mondod, hogy az objektumorientáltság azt mondja, hogy dobjuk ki az oop esszenciáit akkor, amikor nincs értelme, akkor tegyük fel, hogy úgy van. NA DE akkor viszont elkezdődik a classok leeresztése, az oda nem illő attribútumok kiszórása a classekből. ezzel az általad linkelt doom3-mas vektor classokból konkrétan egy betű sem fog maradni, minden rövid, egyszerű C kóddá fog szétpottyanni, egy egyszerű függvénylistává rövid implementációkkal, pointerekkel, ami a sebesség, az egyszerűség, a használhatóságra igencsak jótékony hatással lenne, például jó néhány esetben ki lehetne hagyni az értékadásokat, inicializálásokat, a memory managert, a stacken való felesleges objektumzsonglőrködést a mókából, ráadásul még a headerből is ki lehetne írtani a kódot, ami a cachehasználatra is jótékony hatással lenne valamelyest. (persze utána nem lehetne a+=b módszerrel vektorokat összeadni, hanem le kéne írni kézzel a függvény nevét - nyilvánvalóan szerencsétlen kóder, aki ezt így megcsináltatta valakivel, azt hitte, hogy ezzel majd egyszerűbbé válik a vektorok használata az egész kódban, pedig pont, hogy ezzel rákosította be az egészet, lehet, hogy pont maga JC volt az, nem lepne meg). ennek a kódnak a létezését tehát egyetlen dolog teszi lehetővé - méghozzá az a törekvés, hogy mindenből attribútum legyen, hisz máskülönben azt a maradék egészen kicsi létjogosultságát is elveszti.

-ezzel a kóddal mindenképp kidobod a fürdővízzel a gyereket: vagy az oop miatt lesz szar az egész, vagy ha rendesen meg akarod csinálni, akkor oop nélkülivé válik az egész, tehát eleve megy a szemétbe az egész kód.

-nem mondom, C-ben is lehet olyan fatális szörnyűségeket elkövetni, mint ez a kód. ha ezt 1:1 c-be átírod, akkor is szar marad, de csak akkor nyílik meg a lehetőség arra, hogy normálisan megcsináld.

és elfogytak az egy hozzászólásban legépelhető karakterek, azt hiszem, hogy az általad bemutatott kódrészlettel bemutattam minden aspektusát annak, hogy mi az, ami szerintem végzetesen bajos az oop-vel, tök jó, hogy ezt hoztad fel példának, mert ennél jobb állatorvosi lovat szeirntem keresve sem találhattam volna.

tamareaf 2017.05.16. 02:11:24

@Gerilgfx: Megint kérlek próbáld kettéválasztani az objektum orientált programozást a konkrét programozási nyelvtől. A bejegyzésed elvileg nem a C++-ról szól, hanem az OO-ról általánosságban.

Ugyan úgy kértelek, hogy oszt meg, honnét jutottál arra a következtetésre hogy, A "nem kell mindig kiszámolni a normálvektort, csak ha szűkséges. Tehát létrehoztál egy objektumot, amely vagy nem fog objektumként viselkedni többé, ".

Ide másolom a definíciót a Wikipediáról, ha már arra hivatkoztál:
Encapsulation is an Object Oriented Programming concept that binds together the data and functions that manipulate the data, and that keeps both safe from outside interference and misuse.
Tehát adat és a rajta végezhető függvények összekapcsolása. Nincs szó arról, amit állítasz, hogy a normál vektort ne lehetne épp egy függvényben kiszámítani. Ami a teljes kettes pontodat érvényteleníti.

Kérlek tartsuk a beszélgetést a kettes pontnál, ne hozz be új elemeket. Persze, ha azt nem tudod alátámasztani, megvizsgálhatjuk a többi állításodat is. De mindenképp egyszerre csak egyet.

Gerilgfx 2017.05.16. 03:04:47

@feamatar: a ,,vagy nem fog objektumként viselkedni'' részt nem úgy értettem, hogy megszeged az oop paradigma szabályait, hanem úgy, hogy ez így nem praktikus, mert így ugyanazt csinálod, mint amit objektum nélkül csinálnál, és ehhez az oop nem praktikus. egy vászondzsekihez tornacipőt is felvehetsz, hisz a dzseki-dresszkód engedélyezi, sőt, előírja a cipő viselését is. de ha tornacipőt akarsz viselni, ahhoz nem kell dzseki. a normálvektort kiszámíthatod függvényben, de ahhoz nem kell oop sem. ha én tornacipőt akarok venni, ahhoz még nem feltétlenül húzok vászondzsekit, de nincs arról szó, hogy a tornacipőhöz ne húzhatnál vászondzsekit, csak épp minek húznál hozzá? a téma túl van tárgyalva, és nem látom, hogy az oop mellett állna bármi olyan tény, amit csak azért ne lehetne itt megvilágítani, mert én csak a c++-on keresztül tudom kontextusba hozni.

tamareaf 2017.05.19. 00:20:25

@Gerilgfx: Nem ugyan azt csinálod.
1. Az egységbe zárással kapsz egy stabil API-t.
2. És emellé általában kapsz öröklődést vagy valamilyen interface rendszert.
3. És polimorfizmust.

Ez nagyon erőteljes API-hoz vezethet, lásd például Java Collection API-t.

Példaként, és ezzel az 1-es pontodra is rácáfoljak, ha objektumok fizikáját modellezed, és mondjuk van mind hajó, mind jármű, mind repülő, akár vonatok is, s többféle fizikai model implementációval, akkor valahogy így updateled az összes entity fizikáját többszálon, Javaban:

entities.parallelStream().forEach(e -> e.tick());
süti beállítások módosítása