Posts tagged ‘object-oriented’

Biedny, biedny JavaScript

2011-11-15 21:16

Przyznam, iż jestem trochę zaskoczony. Okazuje się bowiem, że niekiedy zupełnie nie udaje mi się skomunikować tego, co mam w rzeczywistości na myśli. A wydawać by się mogło, że przynajmniej te 500+ notek na blogu powinno dość skutecznie nauczyć mnie, jak klarownie formułować swoje stwierdzenia i opinie. Teoretycznie niby też wiem, że zrozumienie jest często podwójną iluzją, więc z dwóch wyjaśnień należy zawsze wybierać te łatwiejsze i bardziej bezpośrednie – także wtedy, gdy trzeba je dopiero znaleźć. To wszystko wydaje się oczywiste, dopóki – jak się przekonałem – nie okaże się trudne w praktycznym stosowaniu.

O co mi w tym miejscu chodzi? Ano o to, iż niesłusznie zostałem uznany przez kilka osób za – nieco wyolbrzymiając – hejtera JavaScriptu. Tak została przez niektórych odebrana moja niedawna publikacja slajdów z prezentacji pod tytułem The Beauty and the JavaScript; tytułem, który rzeczywiście może dawać co nieco do myślenia ;) I chociaż mógłbym uznać, że wchodzi tu w grę głównie kwestia oceny wykładu po samych slajdach, to jakoś wydaje mi się, że wypadałoby tu dokonać małego sprostowania. Dzięki temu mógłbym też napisać, jak to właściwie jest z tą moją opinią o JavaScripcie, który przecież już od dłuższego czasu jest sam w sobie bardzo nośnym tematem.

Spieszę więc z wyjaśnieniem, że w kwestii JavaScriptu mam raczej osobliwą opinię. Otóż przede wszystkim jest mi go… żal.

class Fish extends Animal?…

2011-09-22 22:24

Pisałem już wcześniej o tym, że ostatnimi czasy programowanie obiektowe nie ma zbyt dobrej prasy i swego rodzaju modą stało się jego krytykowanie. Nie jest to oczywiście trend zupełnie pozbawiony podstaw. Z jednej bowiem strony dla pewnych problemów lepsze wydają się inne paradygmaty: np. dla modelu żądanie-odpowiedź (typowego dla aplikacji webowych) najwyraźniej całkiem dobrze sprawdza się programowanie funkcyjne. Z kolei zastosowania wymagające dużej wydajności (np. programowanie grafiki 3D czasu rzeczywistego) mogą istotnie nie tolerować narzutu związanego z polimorfizmem funkcji wirtualnych – albo przynajmniej tak się wydaje tym, którzy się nimi zajmują.

Sądzę jednak, że spory udział ma tu też pewien powszechny (niestety) zwyczaj krytykowania rzeczy, których nie do końca rozumiemy. Szerokie kręgi zatacza bowiem pewien specyficzny sposób opacznego interpretowania idei OOP-u. Jego źródła upatruję w wielu (może nawet większości) kursach, książkach, tutorialach, artykułach i wszelkiego rodzaju materiałach instruktażowych dla początkujących adeptów programowania. Sam dodałem swój niechlubny wkład do tego stanu rzeczy, do czego się tu otwarcie przyznaję. No cóż, nikt mnie ostrzegł – ani wtedy (czyli jakieś 6 lat temu), ani nawet teraz.
A ostrzeżenie jest absolutnie niezbędne. Także dlatego, że co najmniej raz słyszałem, jak owo mylne pojęcie na temat OOP-u stało się poważnym argumentem w rzeczowej poza tym dyskusji na temat jego zalet i (głównie) wad. Nawet ważniejszym powodem jest jednak to, iż niewłaściwa interpretacja założeń programowania obiektowego może prowadzić do źle zaprojektowanych systemów, które trudno się potem konserwuje i rozbudowuje.

O jakiego więc rodzaju konfuzji tu mówimy?

Moda na krytykowanie OOP-u

2011-03-19 20:47

Nauczyłem się już lubić fakt, że w przypadku informatyki powiedzenie o “ciekawych czasach” jest truizmem, bo ciekawie jest po prostu zawsze – głównie ze względu na tempo zmian w wielu dziedzinach. Nawet w tych, wydawałoby się, zastygłych na lata. Niecałe trzy lata temu zżymałem się na przykład na zbytnią ufność w doskonałość obiektowych metod programowania. Dzisiaj zaś przychodzi mi robić coś zdecydowanie przeciwnego.
Programowanie obiektowe jest obecnie sztandarowym kozłem ofiarnym i chłopcem do bicia, otrzymującym ciosy z wielu stron. Już nie tylko programiści gier twierdzą, że nie mogą sobie na nie pozwolić ze względu na wydajność i zamiast niego forsują Data Oriented Design. Pokazywałem niedawno, że sprzeczność między tymi dwoma podejściami jest raczej pozorna niż rzeczywista. Teraz natknąłem się na interesującą opinię, która podważa sens OOP-u jako metodologii, wychodząc z nieco innego punktu widzenia niż wydajność dla celów grafiki real-time:

Object-oriented programming (…) is both anti-modular and anti-parallel by its very nature, and hence unsuitable for a modern CS curriculum. [pogrubienie moje]

Anty-modularne i anty-współbieżne? Oczywiście; da się napisać kod obiektowy, który te dwa warunki będzie spełniał doskonale. Ale to nie oznacza, że każdy kod obiektowy je spełnia, a to właśnie jest implikowane powyżej. Nie da się tego określić inaczej niż jako stereotyp – i to w modelowej wersji, czyli negatywnego uogólnienia z pojedynczych przypadków.

Jako antidotum na te rzekome bolączki OOP-u często wymieniane jest programowanie funkcyjne. Nie ujmując mu niczego ze swojej elegancji, nie mogę jednak nie zauważyć, że zamiata ono wiele problemów pod dywan. Określanie wykonania programu jako serii transformacji danych nie rozwiązuje jednak problemu: gdzie i jak te dane mają być zapisywane i chronione przed równoczesnym dostępem z wielu ścieżek wykonania. Sytuacje, w których programowanie funkcyjne lub quasi-funkcyjne sprawdza się dobrze to takie, gdzie problemy te dały się w miarę łatwo rozwiązać. Tak jest chociażby w przypadku vertex i pixel shaderów, gdzie podział danych wejściowych i wyjściowych na rozłączne bloki jest wręcz naturalny. Fakt ten nie jest jednak zasługą programowania funkcyjnego, tylko natury zagadnienia – w tym przypadku renderowania grafiki opartej na wielokątach.

I właśnie o tym powinniśmy pamiętać, gdy wyzłośliwiamy się nie tylko na OOP, ale dowolny inny paradygmat programowania. Otóż porzucenie go nie sprawi od razu, że magicznie zaczniemy pisać kod doskonale modularny. A już nie pewno nie spowoduje, że niezwykle trudne zagadnienia współbieżności staną się nagle banalnie proste. To niestety tak nie działa.
Nie znaczy to oczywiście, że nie powinniśmy poszukiwać nowych, lepszych metodologii do konkretnych zastosowań. Dlatego przecież wiele języków (np. C++, C#, Python) ewoluuje w kierunku wieloparadygmatowości, aby możliwe było dobranie właściwych narzędzi dla danej sytuacji. Nie wydaje mi się jednak, aby uleganie trendy nurtom krytykowania jakichkolwiek rozwiązań poprzez odwoływanie się do stereotypów i nieuzasadnionych wyobrażeń o nich było w tym procesie specjalnie produktywne. Zdaję sobie jednak sprawę, że “funkcje wirtualne to zuo!” brzmi lepiej niż “wywoływanie funkcji wirtualnych skutkuje narzutem wydajnościowym związanym z dodatkowym adresowaniem pamięci (które nie jest cache-friendly) i może powodować niepożądane skutki uboczne, jeśli ich wersje w klasach pochodnych nie są thread-safe“. Mam jednak nadzieję, iż nikt nie ma wątpliwości, które z tych dwóch stwierdzeń jest bardziej racjonalne.

Podziękowania dla Rega za podesłanie linków, które zainspirowały mnie do podjęcia tego tematu.

Obiekt na chwilę

2010-12-02 21:58

Swego rodzaju miejską legendą pewnego forum nt. programowania jest “algorytm” znany pod intrygującą nazwą sortowania przez ListBox. Adept kodowania postawiony przed problemem posortowania listy obiektów postanowił mianowicie, że akceptowalnym rozwiązaniem dla niego jest następująca sekwencja czynności:

  1. Stworzenie obiektu kontrolki typu listbox, czyli typowej przewijalnej listy elementów, która byłaby niewidoczna, niepodłączona pod hierarchię kontrolek w interfejsie lub po prostu miała zerowe rozmiary.
  2. Wypełnienie jej zawartości na napisy odpowiadające elementom do posortowania.
  3. Ustawienie właściwości Sorted tej kontrolki na true, dzięki czemu jej elementy (wcześniej dodane) będą zawsze posortowane.
  4. Pobranie zawartości kontrolki, którą są posortowane elementy.

Genialne, nieprawdaż? :) Zauważmy, że to kreatywne rozwiązanie trudnego problemu wymagało zaledwie jednego dużego i skomplikowanego obiektu, który zasadniczo jest też z zupełnie innej bajki (bo z warstwy GUI) niż kod logiki programu, który to zapewne potrzebował rozwiązania. No ale w końcu programowanie premiuje myślenie wybiegające poza schematy, więc nie ma chyba żadnego powodu, żeby powyższy sposób uznać na niewłaściwy, czyż nie? ;-)

Żarty żartami, ale… No właśnie, w rzeczywistości zastosowane tu “podejście” nie jest wcale tak obce niektórym faktycznym rozwiązaniom rzeczywistych problemów programistycznych. Na wiele pytań odpowiedzią jest bowiem często utworzenie obiektu “tylko na chwilę” – zazwyczaj jedynie dla wywołania jednej jego metody.
Weźmy na przykład pobranie aktualnego zrzutu stosu (stacktrace) w Javie. Prawdopodobnie najmniej kłopotliwą metodą jest utworzenie obiektu wyjątkopodobnego (Throwable) i i wywołanie jego metody getStackTrace:

  1. StackTraceElement[] stacktrace = new Throwable().getStackTrace();

Jest to na tyle nietypowe, że pewnie sporo osób odruchowo otoczyłoby instrukcję konstruującą obiekt nawiasami, chociaż nie jest to składniowo wymagane.
Inny przykład? Dokonanie HTML-owego escape‘owania tekstu w JavaScripcie wspomaganym biblioteką jQuery. W tym celu tworzy się nigdzie nieprzyłączony węzeł DOM, ustawia jego zawartość tekstową i natychmiast ją pobiera:

  1. function htmlEscape(str) {
  2.     return $("<div/>").text(str).html();
  3. ]

I wreszcie rzecz ze znanego i lubianego podwórka C++: konwersja liczb do i z formatu binarnego przy pomocy chwilowych obiektów typu bitset:

  1. const size_t BITS = 8 * sizeof(unsigned long);
  2. unsigned long bin2long(const string& str) { return bitset<BITS>(str).to_ulong(); }
  3. string long2bin(unsigned long n)
  4.     { return bitset<BITS>(n).to_string<char, char_traits<char>, allocator<char> >(); }

Podobnych przykładów dałoby się znaleźć oczywiście znacznie więcej. Fakt ten nie jest zupełnie obojętny dla programistów, jako że przynajmniej w niektórych językach utworzenie obiektu może być operacją dość kosztowną. Nie dotyczy to akurat C++, gdzie możliwe jest alokowanie dowolnych obiektów na stosie, lecz raczej tych platform, gdzie obiekty tworzy się na stercie. Często mają też one stały, dodatkowy narzut na sam fakt swego istnienia, spowodowany odziedziczeniem funkcjonalności po klasie “najbardziej bazowej” (zwanej zwykle Object) – narzut zarówno czasowy, jak i pamięciowy. Dlatego też wielokrotne tworzenie małych i krótko żyjących obiektów może być poważnym uszczerbkiem wydajnościowym. Można jednak liczyć na to, że z biegiem czasu sytuacja pod tym względem będzie się poprawiać – tak jak chociażby w przypadku Javy i wprowadzonych optymalizacji w obsłudze obiektów typu String.

Tags: , , , ,
Author: Xion, posted under Programming » 1 comment

Obiektowy szowinizm

2008-08-08 22:00

Od jakiegoś czasu najpopularniejszymi językami programowania są albo te stricte obiektowe, albo chociaż oferujące przynajmniej najważniejsze cechy tego modelu programowania (czyli dziedziczenie, polimorfizm i metody wirtualne). Prawdopodobnie większość powstającego kodu realizuje więc założenia OOP-u co najmniej w takim stopniu, że można go uznać za spełniający paradygmat obiektowy – albo chociaż podpadający pod obiektowość bardziej niż pod cokolwiek innego.
Ano właśnie: warto od czasu do czasu zauważyć, że oprócz OOP-u istnieje też “coś innego”, i że obiektowy model programowania wcale nie jest jedynym. Nie musi być on też ani ostatecznym, ani najbardziej uniwersalnym. A już tym bardziej nie jest on jedynie słusznym.

Jako koderzy podążający za wytycznymi programowania obiektowego często jednak tak uważamy – mniej lub bardziej świadomie. Zwłaszcza, że obecnie można zajmować się programowaniem całkiem długo i nawet nie słyszeć o innych paradygmatach niż obiektowy. A jeśli nawet ktoś na podobne “ciekawostki” lub na “dziwaków” opowiadających się na innym podejściem do kodowania, to najpewniej nie będzie to miało żadnego wpływu na jego dobre samopoczucie i przekonanie o wyższości OOP-u nad czymkolwiek innym.
Bo przecież łatwo znaleźć programistów myślących bardzo podobnie i bez wysiłku wyciągnąć całe mnóstwo silnych argumentów na poparcie swoich racji. Bodaj najczęściej wykorzystywanym jest ten mówiący o odpowiednim poziomie abstrakcji, który jest jakoby immanentną cechą programowania obiektowego. Z jednej strony jest on bowiem wyższy od brzydkiego programowania strukturalnego, dzięki czemu kod obiektowy łatwiej jest napisać i zrozumieć. Jednocześnie nie jest to też poziom zbyt wysoki, przez co nadal wiadomo, jak nasz program działa i jak z grubsza sprawuje się pod względem wydajnościowym. Tego samego nie można rzecz jasna powiedzieć wtedy, gdy kodujemy funkcyjnie czy deklaratywnie.

Wszystko to brzmi rozsądnie i wydaje się słuszne. W rzeczywistości jednak posługiwanie się takimi kryteriami jest zwykłym nadużyciem. Na takiej zasadzie można by narzekać na to, że nie da się przygotować omletu przy pomocy samego widelca (że pozwolę sobie posłużyć się analogią kulinarną ;]). Należy bowiem zawsze mieć na uwadze to, o jakim zastosowaniu mówimy. Programowanie nie jest przecież dziedziną abstrakcyjną, ale jak najbardziej praktyczną, niezależnie od tego, jak bardzo usiłowalibyśmy ją steoretyzować.
Dlatego też absurdem jest twierdzenie o wyższości programowania obiektowego nad innymi paradygmatami. Bo czy bawilibyśmy się w tworzenie klas w przypadku takiego oprogramowania jak firmware procesora czy karty graficznej, działającego w ścisłym powiązaniu ze sprzętem? I czy odpowiadałoby nam, gdyby zamiast określania za pomocą znaczników wyglądu fragmentów strony WWW bylibyśmy zmuszeni tworzyć dla każdego z nich osobny obiekt i ustawiać jego właściwości?…

Nie zamykajmy się więc w swoim obiektowym światku, nawet jeśli czujemy się w nim nadzwyczaj dobrze. Znajomość innych sposobów kodowania może nam bowiem tylko pomóc.

Tags: ,
Author: Xion, posted under Programming, Thoughts » 4 comments
 


© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.