Posts tagged ‘oop’

Introduction (OOP principles)

Today I’d like to present you a problem that most especially rookie developers find compelling. This is strongly connected with OOP basics, specifically with 2 fundamental truths:

  1. Use inheritance whenever possible.
  2. Prefer composition over inheritance.
So at first I had problems understanding how these 2 rules are related but as the time passed I learned to distinguish the two and recently in one of my projects I came across piece of code that is perfect example on why object composision/aggregation might be a better solution over inheritance.

Old way – using inheritance

Background – code usage

To start with some background – the code referred to is part of application that displays daily trend graph of some piece of data. It’s responsible for drawing coordinate system, x-axis, y-axis, some labels, legend lines, text-labels and of course data-curves. The code is executed on client-side and one of requirements is to support ie8 – which is why there was a need to support both SVG and VML drawing formats.

Classes responsibilites

The old apporach used in inheritance to support both formats and below you can find class diagram for the described classes. To start from the top:

  • GrapDrawer is a drawing interface – it’s main goal is to provide high-level methods for drawing different parts of graph used by othere pieces of application
  • AbstractGraphDrawer which is an interesting beast – because it provides a bridge between GraphDrawer interface and client-specific implementations – that is VML/SVG achieved set of abstract protected methods that encapsulate client-specific drawing API
  • SVGDrawer/VMLDrawer – these are both client-specific drawing apis.

Problem description

You might be asking yourselves why is there any problem with this approach. It has all the good parts:

  • there’s an interface for accessing public methods,
  • there’s an abstract method that acts as a bridge between drawer and
  • client-specific implementation.

Everything is encapsulated so user has no knowledge of what’s going on behing the secenes – so what’s the big deal.

This is all true but due to AbstractGraphDrawer dual nature it’s code is really hard to maintain. Both high and low-level API collide with each other – the former changes frequently where the latter very rarely. If you look closer you can see that all protected methods are there only to be overridden by implementation and they’re completely hidden from user. While all parts of public interface are not used in any way by the implementation.

New way – use object aggregation

Solution description

These two worlds interact with each other only through their interfaces. So it’s a perfect candidate for split – low-level methods should be hidden behind an interface that must be implemented by client-specific code, whereas high-level methods, used by some other code go to a public class which has reference to client-specific low-level drawing api.

This is all presented in the diagram below, where you can find:

  • GrapDrawer class which is used for high-level operations. Low level operations are executed by graphDrawerWorker
  • GraphDrawerWorker interface which defines set of required low-level operations
  • SVGDrawer/VMLDrawer classes which only implement GraphDrawerWorker and thus loose all coupling with high-level code

Summary

There’s still at least one question that needs some attention: how did this code creep into the application? The answer is fairly simple – it was built incrementally as business needs rose and suddenly AbstractGraphDrawer became a beast with two heads. Unfortunately for everyone who’s been working with it for longer time it was hidden. Only when someone with fresh look apporached a project, not only could this be spotted but also addressed.

All of you that can spot more basic OOP principles broken in original code (or a new one :P) please leave them in comments 🙂

Kontynuuje moje poszukiwania narzędzi i informacji nt. tworzenia rozszerzeń języka php, jednak niestety tutki na zend.com autorstwa Sary Golemon kończą się w miejscu najbardziej dla mnie interesującym czyli jak tworzyć obiekty/interfejsy/iteratory, niby jest zapowiedź kolejnej części, ale wątpię, żeby ona kiedykolkiek ukazała się w witrynie, bo Sara po pierwsze wydała książkę nt pisania rozszerzeń (niestety nie znalazłem polskiego wydania), a po drugie od tej zapowiedzi minęły już 4 lata. Nicto trzeba szukać dalej, troche guglania i znowu jakis skrawek informacji, na blogu niejakiego Ananta można tam znaleźć link do tutka Marcusa Boergera, który skupia sie na OOP właśnie, ale niestety i on jest już chyba dość przestarzały, bo nie obyło się bez problemów podczas kompilacji kodu, ale wystarczył szybki rzut oka w inne moduły i źródła zend engine, żeby odkryć rozwiązanie (open-source się sprawdza :D). Niestety pisanie modułów w ten sposób napewno nie przypomina dobrej zabawy, te wszystkie makra, długaśne nazwy funkcji, haki na wielowątkowość markami z rodziny TSRMLS_*, no np. żeby się przespacerować po tablicy trzeba użyć takiego potwora:

for(
zend_hash_internal_pointer_reset_ex( arr_hash, &pointer );
zend_hash_get_current_data_ex(arr_hash, (void**)&data, &pointer ) == SUCCESS;
zend_hash_move_forward_ex(arr_hash, &pointer )
){
// tutaj ma sie cos dziac
}

Nie, to zdecydowanie nie jest to co tygryski lubią najbardziej :/

Anant podaje link go generatora kodu rozszerzeń, dostępnego w repozytoriach pear/pecl, które się nazywa CodeGen_PECL, ale po doświadczeniach z boost::python i łyku elgancji i prostoty z jaką można tworzyć rozszerzenia zapragnąłem czegoś podobnego, już już zacząłem obmyślać koncepcje kiedy zapaliła się żarówka – może nie tylko mnie zrobiło sie niedobrze na widok tej gmatwaniny i już coś takiego napisał? Jak się zapewne domyślacie tak jest. Po wpisaniu w guglu boost php, wyskakuje strona projektu o tejże nazwie, autorstwa Morioshiego. Sama biblioteka chyba nie została nigdy zgłoszona do komitetu akceptacyjnego boost.org, a może coś przegapiłem 🙂

Skontaktowałem się z autorem w sprawie dopisania paru rzeczy i obiecał dodać mnie do projektu, no to cytując kapitana planete „Goooo Planet!”.