Archiwum miesiąca: czerwiec 2018

Progressive Web App w ekosystemie e-commerce

Progressive Web App (PWA) to rozwiązanie, które dopiero zaczyna pojawiać się w kontekście e-commerce. Powszechnie kojarzy się tylko z nowoczesnymi platformami, jednak jej idea oraz główne założenia mają głębszy sens i coraz częściej znajdują zastosowanie w systemach sprzedażowych.

Cechy Progressive Web App

Progressive Web App zaprojektowane zostało w celu zapewnienia klientowi jak najlepszych doświadczeń, niezależnie od tego z jakich urządzeń korzysta. Takim urządzeniem może być desktop, smartfon, telewizor, a w przyszłości także inne nośniki z dostępem do internetu. Z punktu widzenia użytkownika, PWA działa jak aplikacja mobilna, jednak uruchamiana jest jak standardowa strona internetowa czy serwis transakcyjny. Aby rozwiązanie spełniało cechy PWA, musi być m.in.: w pełni responsywne, serwowane przez protokół https, w celu zapewnienia bezpieczeństwa, opisane przez plik manifest.json, umożliwiające wysyłanie notyfikacji użytkownikom oraz działające także w trybie offline.

Działanie Progressive Web App w trybie offline

Wśród czynników wyróżniających PWA na tle innych rozwiązań mobilnych podaje się właśnie możliwość jej działania w trybie offline. Dzieje się to dzięki procesom Service Workers, które ściągają część danych w tle, podczas korzystania użytkownika z aplikacji. W czasie tworzenia Progressive Web App, można precyzyjnie określić metodę działania Service Workers i tego, jak dużo działań ma być wykonywanych w tle. PWA bardzo dobrze radzi sobie również w momentach ograniczonego dostępu do internetu.

Różnica miedzy Progressive Web App (aplikacją webową), aplikacja mobilną i responsive web design

Pisząc o rozwiązaniach mobilnych, często spotykamy się z wieloma, podobnymi nazwami. Warto więc sprecyzować, czym dokładnie charakteryzują się poszczególne rozwiązania.

– Aplikacja mobilna, tworzona jest wyłącznie na urządzenia mobilne. Z punktu widzenia funkcjonalności, aplikacje mobilne są najbogatszym rozwiązaniem, z którego użytkownik może korzystać na smartfonie. Oferują one bowiem użytkownikom możliwości wysyłania push notyfikacji, wykorzystania skanera kodów kreskowych czy użycia beaconów (w celu ustalenia lokalizacji).

– PWA (aplikacja webowa) to rozwiązanie, które w swojej idei oddziela frontend od backendu, zwana także jako headless ecommerce Jest to aplikacja internetowa uruchamiana tak jak zwykła strona internetowa działająca po stronie przeglądarki użytkownika, ale kreująca wrażenie działania na zasadzie natywnej aplikacji mobilnej.

– Aplikacja systemu – w powszechnym znaczeniu są to wszystkie rozwiązania i komponenty składające się na działanie systemu. W kontekście e-commerce można odnieść to do całego core danego oprogramowania.

– Responsive Web Design to technika projektowania systemu, która umożliwia jak najlepszą jego prezentację wizualną, niezależnie od rodzaju urządzenia, na którym wyświetlane są treści. Dzięki jej zastosowaniu, wygląd systemu i układ wykorzystanych w nim treści są automatycznie dostosowywane do rozmiaru okna przeglądarki, z poziomu której system jest wyświetlany.

Główna idea PWA – hermetyzacja zadań

Skoro istnieją bogatsze w funkcje rozwiązania mobilne, pojawia się pytanie, dlaczego warto zwrócić uwagę na Progressive Web App? Na początku trzeba mieć świadomość, że słowo app, w kontekście PWA, nie do końca dotyczy rozwiązań mobilnych. Chodzi bardziej o aplikację i budowę całego systemu, który przy okazji będzie się dobrze wyświetlał na urządzeniach mobilnych.

Główną ideą Progressive Web App jest poprawa wydajności i szybkości działania systemów. Dzieje się to za pomocą hermetyzacji zadań, czyli budowania systemu w taki sposób, aby jedna jego część odpowiadała tylko za jedną wykonywaną czynność.

System transakcyjny sprowadza się do części backendowej, czyli serwerowej oraz frontendowej, którą nazwać można kliencką. Komunikację między tymi dwoma komponentami umożliwia REST API, wykorzystujące format JSON. Komunikacja odbywa się poprzez protokół HTTP, czyli o konkretne dane, wysyłane jest konkretne zapytanie. W takim modelu, serwer jest tylko wykonawcą zapytań, dzięki czemu jest on dużo szybszy.

Sama praca nad systemem też jest podzielona między frontendem a backendem. Odrębne zespoły pracują nad niezależnymi jednostkami bez wzajemnej ingerencji, przy czym system nadal działa jako całość. To sprawia, że proces wdrożenia i rozwoju jest bardziej poukładany i istnieje większa kontrola nad projektem.

Progressive Web App dla użytkownika końcowego

Stworzenie części frontendowej w rozwiązaniu PWA może wizualne dużo nie różnić się od standardowego rozwiązania. Dla klientów jednak, zauważalnych będzie kilka istotnych różnic:

– szybsze działanie strony poprzez lepszą logikę funkcjonowania poszczególnych części składowych – przyspieszenie nawet o 30%,

– poprawa UX, a co za tym idzie, lepsze doświadczenie zakupowe,

– możliwość odczuwania takich samych doświadczeń zakupowych, niezależnie od rodzaju wykorzystywanego przez użytkownika urządzenia.

Progressive Web App dopiero zaczyna pojawiać się w kontekście e-commerce. Pierwsze badania przeprowadzone przez 5 Miles czy Alibaba pokazują, że jest to rozwiązanie potrafiące podnieść konwersję (nawet o 76%), poprawić wydolność systemów (nawet o 88%), a także zmniejszyć ilość wykorzystywanych danych nawet o pięć razy. Wszystkie te czynniki oraz przeprowadzone w ramach działań Research & Development i-systems prace, zaowocowały powołaniem zespołu kontekstowego, odpowiedzialnego za Progressive Web App. O kolejnych działaniach tego zespołu oraz jego pierwszych wdrożeniach będziemy informować na blogu i-systems. Już teraz zachęcamy do lektury.

Zapisz się do newslettera

#224 Lean Management w e-commerce

Lean Management jest metodologią, której celem jest poprawa wyników biznesowych, poprzez dążenie do zmniejszenia ilości czynników generujących zbędne koszty w całym procesie. Mowa tutaj o wszystkim: o niepotrzebnym drukowaniu papierowych dokumentów o poprawie obiegu informacji, czy ulepszeniu procesów produkcji. Wywodzi się ona właśnie z sektora produkcyjnego, ale coraz częściej wykorzystuje się w sektorach usługowych, a także w e-commerce. Lean Management stawia klienta na pierwszym miejscu. Organizacja musi określić jakie są oczekiwania klienta, jakie są dla niego ważne wartości, a następnie dopasować się do nich i poczynić to w jak najlepszy, a jednocześnie jak najbardziej optymalny sposób. Największe marki nie ukrywają, że korzystają z niej w swojej codziennej działalności, warto sprawdzić dlaczego.

Z dzisiejszej lekcji dowiesz się:

    • czym jest Lean Menagement;
    • jak sprawdza się w e-commerce.

Dlaczego Lean management?

Trzeba zacząć od tego, że klienci, którzy kupują online, robią to w sposób dla nich najwygodniejszy. Wybierają takie sklepy, które mogą zrealizować ich potrzebę w sposób szybki i bezproblemowy. Dla wielu cena gra rolę, ale nadal są tacy, którzy mogą zapłacić więcej, jeśli mają pewność, że zostaną oni odpowiednio obsłużeni. Należy pamiętać, że są oni świadomi cen, potrafią je sprawdzać, często je porównują i analizują u którego sprzedawcy zakup jest najbardziej opłacalny. Średnio przed podjęciem decyzji zakupowej e-konsumenci przeglądają trzy witryny internetowe. By sprzedawca mógł więc być konkurencyjny wobec innych handlowców, nie powinien walczyć tylko ceną, bowiem doprowadza to do sytuacji psujących rynek. Należy więc zwiększyć wartość dodaną do usługi, polepszyć jakość obsługi klienta i stworzyć procesy, które będą perfekcyjne, na przykład obniżenie czasu realizacji zamówień, czy zwiększenie poziomu zadowolenia klientów.

Marki dbają także o swój wizerunek. Oczywiście nadal pojawiają się brandy, które potrafią strzelić sobie samobója w komunikacji z klientem, ale tego typu działań powinno być coraz mniej. Niestety, w dobie powszechnego dostępu do internetu – kryzysy wypływają na szerokie wody sieci bardzo szybko. Wracając do marek: koncentrują się one na kliencie, ale pokazują też, że są sfokusowane na problemy społeczne czy ekologiczne. Przykładowo w 2012 56% konsumentów na świecie przykładało uwagę do problemów ekologicznych, w 2015 było to już 61%. W ubiegłym roku badanie przeprowadzone w UK pokazało, że 70% ankietowanych menadżerów wysokiego szczebla stwierdziło, że zrównoważony wizerunek marki jest siłą napędową wzrostu i innowacji w firmie. Koncepcja lean bardzo dobrze się do tego wpasowuje. Ograniczenie zbędnych kosztów, materiałów i innych elementów, może być jednym ze sposobów na uzyskanie przewagi konkurencyjnej.

Trzy etapy wdrożenia Lean w logistyce dla e-sklepów

Zarządzanie Lean w dystrybucji opiera się na trzech filarach: możliwości reagowania na pełny popyt, dostarczanie przesyłek w obiecanym terminie oraz utrzymanie zapasów magazynowych przy minimalnych kosztach. W e-handlu sprzedawcy muszą dostarczyć klientowi produkty bez uszkodzeń. W środowisku dystrybucyjnym istnieje zagrożenie, że coś może pójść nie tak, szczególnie, że wiele procesów wykonywanych jest ręcznie, a czynnik ludzki może zwodzić, tak samo, jak automatyczny. Lean Management w czasie rzeczywistym koncentruje się na natychmiastowym wykryciu nieprawidłowości w procesie. Jeśli odpowiednio wcześnie zauważymy na przykład, że towar jest uszkodzony lub uszkodzone jest pudełko, w którym go wysyłamy – unikniemy problemów na późniejszym etapie.

Lean Management może również pomóc w zapobieganiu buforowaniu towarów, na przykład poprzez dynamiczne pobieranie zamówień za pośrednictwem aplikacji, a także poprzez odpowiednie przeszkolenie pracowników, aby zamówienia były przetwarzane tak szybko, jak to możliwe. Jeśli tak się dzieje, to zapotrzebowanie na nadwyżki zapasów znika. Dodatkowo ważne w Lean jest wyeliminowanie niepotrzebnych procesów i zachowań w obsłudze klienta. Generowanie papierowych dokumentów warto zastąpić elektronicznymi, optymalizacja pracy BOK wpływa na minimalizację kosztów stałych, może przyczynić się do ogólne niższych kosztów i atrakcyjniejszej ceny detalicznej

Warto podejrzeć innych

Duzi handlowcy tacy, jak Amazon już od dawna skoncentrowani są na kliencie. Jeff Bezos od początku podkreślał, jak ważny jest dla niego klient, a na wiele jego decyzji mają wpływ zasady Lean. Konkretny przykład znajduje się w podsumowaniu metod transportu na stronie, który koncentruje się wokół obiecanej daty dostawy. Alternatywy transportowe pojawiają się na liście tylko wtedy, gdy mogą spełnić żądany czas dostawy.

Jak można przeczytać w jednym z artykułów „Biorąc pod uwagę ewolucję firmy Amazon z księgarni do sklepu z praktycznie wszystkim, musieliśmy na nowo wymyślić automatyzację, stosując zasadę – utrzymuj ludzi w celu uzyskania wysokiej jakości, złożonej pracy i używaj maszyn do wspierania tych zadań.

Amazon jest kopalnią pomysłów i wiele z nich jest do skopiowania na rodzimym rynku. Paczki przechodzą procesy weryfikacji, powtarzające się problemy z jakimś produktem sprawiają, że jest on blokowany na stronie do wyjaśnienia sytuacji. Bezos przykazuje, by każdy z menadżerów wyższego szczebla przynajmniej jeden dzień przepracował w dziale obsługi klienta i na własne oczy zobaczył, z jakimi problemami boryka się bok. Kaizen, czyli ciągłe doskonalenie się wiąże się z metodologią Lean. W fabrykach Toyoty szefowie także spędzają czas z pracownikami linii produkcyjnych. Czasem dzięki rozmowom i uwagom, można poprawić małe rzeczy, które dają duże oszczędności.

Lean dla każdego

Lean management może być wdrożony w każdym biznesie. To trochę zmiana metod myślenia i zarządzania. W każdym procesie możemy doskonalić się i eliminować z niego błędy. W ten sposób działa na przykład sieć parków Disneya, w których każdy etap zabawy jest pewnym procesem. Błąd w nim może mieć wpływ na pozostałe, dlatego Disney tak bardzo naciskał na testy, analizy, kontakt z klientem, by poprawić każdy z nich. Może warto więc wprowadzić Lean w Twoim sklepie i pozbyć się zbędnych obciążeń i kosztów?

Tagi: #224 Lean Management w e-commerce

Jak sprawnie łączyć dedykowaną ofertę z modelem SaaS?

Od początku działalności naszej firmy, główną, przyświecającą nam podczas realizacji wszystkich projektów ideą jest jakość. Zawsze jednak zastanawialiśmy się nad tym, jak powinna działać organizacja dostarczająca produkty stricte technologiczne, które kierowane są zarówno do dużych, jak i mniejszych klientów. Co zrobić, aby firma była zawsze gotowa na zachodzące na rynku zmiany? W ostatnim czasie, najważniejszym aspektem stało się dla nas znalezienie balansu pomiędzy obsługą dużych, oczekujących stabilizacji klientów a zachowaniem w naszej firmie elastyczności i sprawnej decyzyjności, które są niezbędne w funkcjonowaniu na rynku e-commerce.

W artykule opisujemy innowacyjne rozwiązania i metody, które stworzyliśmy w ciągu ostatnich kilkunastu miesięcy. Opowiadamy również o tym, w jaki sposób nowe możliwości zmobilizowały firmę do zmian organizacyjnych.

Zespół R&D, czyli focus na Continuous Integration

Celem zespołów R&D (Research and Development) jest baczna obserwacja światowych tendencji rynkowych oraz tworzenie takich rozwiązań technologicznych, które pozwolą marce na budowanie przewagi konkurencyjnej. R&D to jednak nie tylko ogromna szansa dla firm – to również swego rodzaju wyzwanie. W krótkim czasie zespoły te będą generować spore koszty, ponieważ rzadko kiedy mogą od razu dostarczyć rozwiązanie, dzięki któremu dana firma będzie na rynku postrzegana jako unikalna. Takie działania wymagają czasu, a co za tym idzie – sporych nakładów finansowych. Nie każda organizacja chce i może sobie na to pozwolić.

W naszym przypadku najważniejszym zadaniem powołanego zespołu R&D stało się wdrożenie metody Continuous Integration, dzięki której klienci otrzymują zupełnie nowy standard systemów sprzedaży. Dla wielu osób akronim CI może brzmieć dość enigmatycznie, jednak dla nas, to jeden z najważniejszych standardów e-commerce na najbliższe lata.

Continuous Integration, czyli ciągła integracja, to jedna z praktyk programowania. Polega ona na pracy całego zespołu programistów, którzy w sposób ciągły wprowadzają zmiany w kodzie. Wspólna praca nad kodem zapewnia najwyższą jakość dostarczanych rozwiązań, ponieważ wytworzony kod jest spójny, a praca systemu efektywna. CI to także nowe podejście do testów. Stałe wprowadzanie zmian do systemu wymaga bowiem przeprowadzania tysięcy automatycznych testów, po których wygenerowany zostaje specjalny raport umożliwiający znacznie szybsze odnajdywanie ewentualnych konfliktów i natychmiastowe ich rozwiązanie. W efekcie, do systemu regularnie wprowadzane są nowe, zawsze dobrze działające funkcjonalności. Dzięki zastosowaniu CI wyeliminowaliśmy również problem związany z aktualizacjami systemów, także tych dedykowanych. Marka posiada dostęp do jedynej, zawsze najnowszej wersji systemu, ponieważ system nie jest wersjonowany. Dodatkowo, jeśli klient chciałby dopasować konkretne rozwiązania do swoich potrzeb biznesowych, to nie stanowi to żadnego problemu – CI nie kłóci się z dedykowanymi rozwiązaniami.

Nowe możliwości motorem napędowym zmian

Wraz z wdrożeniem innowacyjnej metody pracy, mającej wpływ na rozwój obszaru e-commerce obsługiwanych przez nas marek, koniecznym stało się wypracowanie zupełnie nowego modelu biznesowego. Dokonaliśmy zmian technologicznych, za którymi poszły również transformacje organizacyjne – komentuje Jarosław Kubisiak, Dyrektor Zarządzający

Pierwszą z tych zmian była reorganizacja działów IT. Oprócz zespołów kontekstowych, składających się ze specjalistów danej dziedziny, powstały mikrozespoły – odpowiedzialne za konkretne projekty. Na każdy zespół składają się wszystkie kompetencje, niezbędne do realizacji danego celu. Takim celem może być wdrożenie lub utrzymanie danego systemu. Zespół charakteryzuje się sporą dynamiką, ponieważ zmienia on swoje zasoby w zależności od aktualnych potrzeb projektowych. Posiadamy też zespoły na stałe przypisane do danych klientów. Ten model organizacji pracy jest wydajny i bardzo efektywny z punktu widzenia specyfiki współczesnego IT.

Poza organizacją codziennej pracy nad rozwiązaniami, musieliśmy zmienić także kwestie związane z rozliczaniem naszych klientów. System wdrożony w CI od samego początku dostarcza klientom wszystkie funkcjonalności i rozwiązania, które jako firma wypracowaliśmy i rozwijamy od lat. Dodatkowo, żaden klient posiadający system oparty o CI nie ponosi kosztów licencji na poszczególne funkcjonalności. Powstało więc pytanie o to, w jaki sposób sprawiedliwie rozliczać klientów, którzy mają różne potrzeby i prowadzą biznesy o różnej skali. Na bazie lat doświadczeń stworzyliśmy dedykowany model rozliczeń, który pozwala nam zachować elastyczność współpracy.

Dedykowany SaaS, czyli efekt biznesowy wprowadzonych zmian

Stałe dostarczanie do systemu kolejnych elementów i funkcjonalności sprawiło, że oprócz wprowadzenia opisanych już wcześniej zmian, konieczne stało się stworzenie zupełnie nowego modelu biznesowego. Tak właśnie powstała koncepcja modelu o nazwie „Dedykowany SaaS”. Okazało się, że rozwiązania dedykowane i te oferowane w modelu SaaS doskonale ze sobą współgrają. Połączenie dwóch popularnych form e-commerce sprawia, że zostają w pełni wykorzystane ich zalety oraz wyeliminowane minusy.

W efekcie, klient otrzymuje innowacyjny system, który charakteryzuje się:
– niższym kosztem wdrożenia i rozwoju oprogramowania
– możliwością tworzenia dedykowanych rozwiązań
– dostępem do wszystkich funkcjonalności oferowanych przez dostawcę i jego oprogramowanie ecommerce

– szybkim Time to Market
– umożliwieniem wieloletniego rozwoju

Wszystkie zmiany, jakie zaszły w naszej organizacji w ostatnim czasie były dla nas przełomowe. Obok zmiany modelu biznesowego, najważniejszym efektem wszystkich wprowadzanych przez nas zmian jest rosnąca satysfakcja naszych klientów. To właśnie ona sprawia, że każdego dnia podejmujemy coraz to nowe wyzwania technologiczne i regularnie ulepszamy oferowane rozwiązania.

Krótko o SOLID

Podstawowych zasad programowania obiektowego jest wiele. W dzisiejszym wpisie rozważymy jedną z nich, zaproponowaną przez Roberta C. Martina – SOLID.

SOLID to mnemonik pięciu zasad:

S – SRP – Single responsibility principle,
O – OCP – Open/Closed principle,
L – LSP – Liskov substitution principle,
I – ISP – Interface segregation principle,
D – DIP – Dependency inversion principle.

W kilku zdaniach chciałbym przedstawić podstawowe założenia i przykłady dla każdej z tych reguł.

S – zasada jednej odpowiedzialności

Zgodnie z tą zasadą każda klasa powinna mieć tylko jedną odpowiedzialność (innymi słowy: powinien istnieć tylko jeden powód na modyfikację klasy).

Spróbujmy zatem przeanalizować przykładową klasę:

class Person {
    /** string */
    private $firstName;
    /** string */
    private $lastName;

    /** string */
    private $email;

    /** string */
    private $streetName;
    /** string */
    private $buildingNumber;
    /** string */
    private $apartmentNumber;
    /** string */
    private $postalCode;
    /** string */
    private $city;

    public function __construct(string $firstName, string $lastName, string
$email, string $streetName, string $buildingNumber, string $apartmentNumber, string $postalCode, string $city)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->email = $this->validateEmail($email);
        $this->streetName = $streetName;
        $this->buildingNumber = $buildingNumber;
        $this->apartmentNumber = $apartmentNumber;
        $this->postalCode = $postalCode;
        $this->city = $city;
}

    private function validateEmail(string $email) : string {
    if (false === strpos($email, '.') || false === strpos($email, '@'))
{

        throw new Exception('Invalid email');
    }
        return $email;
    }
}

Klasa Person łamie zasadę jednej odpowiedzialności w przynajmniej kilku miejscach. Po pierwsze – pola dotyczące adresu. Klasa nie powinna zawierać pól, które nie są z nią powiązane. Bez problemu można wydzielić je do osobnego obiektu co znacznie ułatwi przyszły refactoring tej klasy (np. dodanie adresu zameldowania, dostawy etc.).

Drugim błędem jest walidator adresu e-mail. Sprawdzenie poprawności adresu nie leży w obowiązku klasy Person. Do tego sama metoda rzuca wyjątek co również jest błędem.

Poprawny kod wygląda np. tak:

class Address {
    /** string */
    private $streetName;
    /** string */
    private $buildingNumber;
    /** string */
    private $apartmentNumber;
    /** string */
    private $postalCode;
    /** string */
    private $city;

    public function __construct(string $streetName, string $buildingNumber,
string $apartmentNumber, string $postalCode, string$city)
    {
        $this->streetName = $streetName;
        $this->buildingNumber = $buildingNumber;
        $this->apartmentNumber = $apartmentNumber;
        $this->postalCode = $postalCode;
        $this->city = $city;
   } 
}

class Person
{
    /** string */
    private $firstName;
    /** string */
    private $lastName;

    /** string */
    private $email;

    /** @var Address */
    private $address;

    public function __construct(string $firstName, string $lastName, string
$email, Address $address)
    {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->email = $email;
        $this->address = $address;
    }

    public function getEmail() : string {
        return $this->email;
    } 
}

class EmailValidator
{
    public static function isValid(string $email): bool
    {
        $hasDot = false !== strpos($email, '.');
        $hasAt = false !== strpos($email, '@');

        return $hasDot && $hasAt;
    }
}

Poprzednia klasa została rozbita na trzy nowe. Każda z nich odpowiada tylko za jedną rzecz. Dodatkowo klasa metoda walidująca poprawność adresu e-mail nie zawiera logiki rzucania wyjątku. Dzięki temu można ją wykorzystać ponownie.

O – zasada otwarte-zamknięte

Zasada OCP oznacza, że klasa powinna być „otwarta na rozszerzenia a zamknięta na modyfikacje”. Uściślając – nie powinno dojść do sytuacji w której trzeba modyfikować kod. Jest to zabronione, gdyż zmiana deklaracji metody może spowodować błędne działanie w innych miejscach systemu.

Rozważmy taki fragment kodu:

class Square {
    /** @var float */
    public $a;


    public function __construct(float $a)
    {
         $this->a = $a;
    }
}

class Circle{
    /** @var float */
    public $r;

    public function __construct(float $r)
    {
        $this->r = $r;
    }
}

class AreaCalculator {

    public function calculate($shape) : float {
        if ($shape instanceof Square) {
            return $shape->a * $shape->a;
        }
        elseif ($shape instanceof Circle) {
            return M_PI * $shape->r * $shape->r;
        }

        return 0.0; 
    }
}

$square = new Square(3);
$circle = new Circle(5);
$calculator = new AreaCalculator;

echo $calculator->calculate($square) . PHP_EOL;
echo $calculator->calculate($circle);

Metoda calculate() z klasy Calculator jest błędna. Dodanie każdej nowej figury wymusza zmianę tej metody, co jest niezgodne z zasadą OCP.

Poprawna implementacja może wyglądać tak:

interface Shape {
    public function area() : float;
}

class Square implements Shape {
    /** @var float */
    public $a;

    public function __construct(float $a)
    {
        $this->a = $a;
    }

    public function area(): float
    {
         return $this->a * $this->a;
    }
}

class Circle implements Shape {
    /** @var float */
    public $r;
 
    public function __construct(float $r)
    {
        $this->r = $r;
    }

    public function area(): float
    {
        return M_PI * $this->r * $this->r;
    }
}

class AreaCalculator {
    public function calculate(Shape $shape) : float {
        return $shape->area();
    }
}

$square = new Square(3);
$circle = new Circle(5);
$calculator = new AreaCalculator;

echo $calculator->;calculate($square) . PHP_EOL;
echo $calculator->;calculate($circle);

Został dodany interfejs, który wymusza implementacje metody area(). Dzięki temu dodając np. trójkąt możemy przekazać go naszemu kalkulatorowi a ten poprawnie zwróci pole figury. Nie wymaga to żadnej zmiany w kalkulatorze.

L – zasada podstawienia Liskov

Ta zasada mówi o tym, że w miejscu klasy bazowej możemy użyć dowolnej klasy, która po niej dziedziczy. Oznacza to, że klasa pochodna musi zachować 100% interfejsu klasy bazowej (wszystkie metody muszą przyjmować te same argumenty i zwracać te same typy).

Spójrzmy na przykład:

class Rectangle {
    private $width;
    private $height;

    public function getWidth() {
        return $this->width;
}

    public function setWidth($width) {
        $this->width = $width;
}

    public function getHeight() {
        return $this->height;
}

    public function setHeight($height) {
        $this->height = $height;
}

    public function getArea() {
        return $this->width * $this->height;
    }
}

class Square extends Rectangle {
     public function setWidth($value) {
        $this->width = $value;
        $this->height = $value;
    }
    public function setHeight($value) {
        $this->width = $value;
        $this->height = $value;
    }
}

Zgodnie z zasadami matematyki wszystko jest w porządku. Każdy kwadrat jest przecież prostokątem. Ale czy w programowaniu rzeczywiście tak jest?

Przeanalizujmy przykładowe użycie:

class Client {
    public function areaVerifier(Rectangle $rectangle)
    {
        $rectangle->setWidth(5);
        $rectangle->setHeight(4);

        return $rectangle->getArea() == 20;
    }
}

class LspTest extends PHPUnit_Framework_TestCase {
    public function testRectangleArea()
    {
        $rectangle = new Rectangle;
        $client = new Client;

        $this->assertTrue($client->areaVerifier($rectangle));
    }

    public function testSquareArea()
    {
        $square = new Square;
        $client = new Client;
 
        $this->assertTrue($client->areaVerifier($square));
    }
}

Pierwszy test przejdzie prawidłowo. Drugi nie. Nasz kwadrat nie zachowuje się jak prostokąt. Łamie prawa geometrii. Ten przykład przy okazji pokazuje, że została złamana nie tylko zasada LSP. Widać tutaj, że programowanie zorientowane obiektowo nie polega na zobrazowaniu prawdziwego życia obiektów. Jeśli będziemy próbować odwzorować jeden do jednego rzeczywistość, prawie zawsze się zawiedziemy.

Zobaczmy jeszcze taki przykład:

class BlackCoffeMachine {
    public function brew() {
        echo 'Pour coffe to the cup' . PHP_EOL;
        echo 'Pour water to the cup' . PHP_EOL;
    }
}

class WhiteCoffeMachine extends BlackCoffeMachine {
    public function brew() {
        parent::brew();
        echo 'Pour milk to the cup' . PHP_EOL;
    }
}

$machines = [
    new BlackCoffeMachine,
    new WhiteCoffeMachine
];

foreach ($machines as $machine) {
    $machine->brew();
}

Zachowuje on zasadę podstawienia. Metoda brew() rozszerza metodę z klasy bazowej zachowując kontrakt, w związku z tym obie klasy mogą być używane wymiennie.

I – Segregacja interfejsów

Zasada mówi, że nie powinno się wymuszać implementacji interfejsów które nie są używane. Innymi słowy: klienci nie powinni zależeć od interfejsów, których nie używają. Oznacza to, że lepiej zdefiniować wiele mniejszych interfejsów niż jeden wielki.

 interface WorkerInterface {
    public function work();
    public function sleep();
}

class HumanWorker implements WorkerInterface {
    public function work() {
        return 'human working';
}

    public function sleep() {
        return 'human sleeping';
    }
}

class AndroidWorker implements WorkerInterface {
    public function work() {
        return 'android working';
    }
    public function sleep() {
        return null;
    }
}

class Capitan {
    public function manage(WorkerInterface $worker) {
        $worker->work();
        $worker->sleep();
    }
}

Robot nie potrzebuje snu, więc implementacja metody sleep() zwraca null. Można tu przy okazji zauważyć złamanie zasady LSP (różne typy zwracanych danych dla różnych implementacji).

Spróbujmy przeanalizować poprawiony kod:

interface WorkableInterface {
    public function work();
}

interface SleepableInterface {
    public function sleep();
}

class HumanWorker implements WorkableInterface, SleepableInterface {
    public function work() {
        return 'human working';
    }

    public function sleep() {
        return 'human sleeping';
    }
}

class AndroidWorker implements WorkableInterface {
    public function work() {
        return 'android working';
    }
}

Interfejsy zostały podzielone, każdy obiekt implementuje tylko to, czego rzeczywiście wymaga. Ale co z klasą kapitana? Czy może ona wyglądać tak:

class Capitan {
    public function manage($worker) {
        $worker->work();
        if ($worker instanceof SleepableInterface) {
            $worker->sleep();
        } 
    }
}

Oczywiście, że nie. Jest tu złamana zasada OCP. Przykładowa poprawna implementacja może wyglądać tak:

interface WorkableInterface {
    public function work();
}

interface SleepableInterface {
    public function sleep();
}

interface ManageableInterface {
    public function beManaged();
}

class HumanWorker implements WorkableInterface, SleepableInterface,
ManageableInterface {
    public function work() {
        return 'human working';
    }

    public function sleep() {
        return 'human sleeping';
    }

    public function beManaged() {
        $this->work();
        $this->sleep();
    }
}

class AndroidWorker implements WorkableInterface, ManageableInterface {
    public function work() {
        return 'android working';
    }

    public function beManaged() {
        $this->work();
    }
}

class Capitan {
    public function manage(ManageableInterface $worker) {
        $worker->beManaged();
    }
}

D – Dependency Inversion

Zasada Odwrócenia Zależności mówi o tym, że moduły wysokopoziomowe nie powinny zależeć od modułów niskopoziomowych. Wszystkie zależności powinny w jak największym stopniu zależeć od abstrakcji, a nie od konkretnego typu.

Spójrzmy na ten prosty przykład:

class MySQLConnection {
   public function connect()
   {
       //
   }
}

class PasswordReminder {
    private $dbConnection;

    public function __construct(MySQLConnection $connection)
    {
        $this->dbConnection = $connection;
    }
}

Nasza klasa do przypominania haseł wymaga połączenia do bazy danych. W tym przypadku wymagany jest obiekt klasy MySQLConnection. A co, gdybyśmy chcieli zmienić silnik bazy danych? Dla klasy PasswordReminder nie powinno mieć znaczenia, jaki jest typ bazy danych. Można to w łatwy sposób naprawić:

interface DbConnectionInterface {
    public function connect();
}

class MySQLConnection implements DbConnectionInterface {
    public function connect()
    {
        // 
    }
}

class InFileConnection implements DbConnectionInterface {
    public function connect()
    {
        // 
    }
}

class PostgresConnection implements DbConnectionInterface {
    public function connect()
    {
        //
    }
}

class PasswordReminder {
    private $dbConnection;

    public function __construct(DbConnectionInterface $connection)
    {
        $this->dbConnection = $connection;
    }
}

W ten prosty sposób uniezależniliśmy przypominanie haseł od jakiegokolwiek silnika. Teraz jego zależnością jest połączenie z bazą a nie konkretny silnik. Sprawiliśmy, że zależność wymaga abstrakcji a nie konkretnej implementacji.

Podsumowanie

Znajomość zasad SOLID na etapie projektowania aplikacji pozwala uniknąć wielu błędów. Stosując je znacząco ułatwimy sobie rozwój naszej aplikacji w przyszłości. Wyrobienie dobrych praktyk programistycznych z pewnością zapunktuje w przyszłym życiu zawodowym.

Tym wpisem chciałem tylko zasygnalizować, że jest coś takiego jak SOLID. Pokazałem kilka prostych przykładów, jednak temat jest dużo szerszy. Mam nadzieję, że zaciekawiłem Cię na tyle, że zaczniesz stosować je w swoim życiu.

Opracowano na podstawie https://laracasts.com/series/solid-principles-in-php/

Autorem tekstu jest Łukasz Wojtyczka.

#223 Dlaczego blogi i vlogi nadal są świetnym medium sprzedażowym i informacyjnym?

O tym, jak bardzo popularna stała się współpraca z wszelkiego rodzaju blogerami – tymi, którzy tworzą treści na Instagramie, autorami, którzy publikują na własnych platformach, a także z vlogerami zamieszczającymi filmy na Youtube – może świadczyć to, że pojawiają się kolejne firmy i platformy pomagające markom nawiązać kooperację z twórcami. Sieci afiliacyjne cieszą się zainteresowaniem obu stron, a odbiorcy treści reklamowych po prostu ufają blogerom. Dlaczego nadal warto inwestować w blogi i tworzyć treści, które sprzedają? Czytaj dalej