Diese 5 Fehler musst Du bei Objektorientierung vermeiden

Objektorientierter Code kommt nicht sauber zur Welt. Du musst aufräumen. Mit Clean Code Richtlinien (siehe Clean Code Kochbuch für PHP-Entwickler) verschönern.

Einige Punkte machen Code schlecht lesbar. Andere Fehler führen zu Problemen.

Du kannst Dein Projekt nicht mehr anpassen. Wenn es zu einem Fehler kommt wird die Fehlersuche schwierig. Es ist für andere Entwickler schwerer, sich in Code einzulesen. 

Verwirrende Zeilen im Code verstehst Du in einigen Wochen nicht mehr.

Die Liste kannst Du mit jedem anderen Problem fortführen.

Von allen die größte Sünde sind…

1. Lange Methode

Wenn Deine Methoden mehr als eine Aufgabe erfüllen, werden sie länger. Ein gängiger Fehler beim Einstieg. Gerade wenn die Zeit drängt.

Typisches Symptom sind Methoden mit Sektionen:

class ImportModel
{
    // ...

    public function executeImport()
    {
        $data = $this->importSource->getData();

        // walk through data
        $products = [];
        foreach ($data as $product) {
            // ...
        } 

        // set images
        foreach ($products as $product) {
            $images = $this->imageGallery->getImages($product);
        }

        // do something else...
    }
}

Kommentare unterteilen die Methode in Bereiche. 

Der einfachste Weg aufzuräumen: Schreib für jeden Abschnitt eine Methode. Die Arbeitsschritte sind markiert. Zeit sie auszulagern.

Zerteile die Methode in mehrere Teile. 

Mehr dazu findest Du auch im Artikel: 

Objektorientiertes PHP verbessern – immer kurze Methoden schreiben

Ebenfalls ein gravierendes Problem entsteht durch…


2. Zu viel Code in einer Klasse

Wenn Deine Klassen unübersichtlich wirken, sind sie meist zu lang. Mit zu vielen Methoden verlierst Du die Übersicht.

Und nicht nur das. Wenn Du nicht sauber arbeitest, kannst Du Dein Projekt später nur sehr schwer erweitern. 

Typisches Problem: bei größeren Änderungen der Anforderungen musst Du viel bestehenden Code verändern. 

Ein Zeichen für Probleme, die tiefer liegen.

Ok, nun kennst Du das Ei. Du hast aber leider noch lange nicht das Huhn. Es fehlt eine Richtlinie.

Eine Hilfe sind die SOLID-Prinzipien. Besonders das S wie…

Single-Responsibility Prinzip

Eine einfache Lösung, die gleichzeitig Spielraum für Interpretationen lässt:

“Jede Klasse ist für eine Aufgabe verantwortlich”. Jede Klasse dient nur einem Zweck. Es gibt trotzdem oft mehrere Lösungen. 

Aber es hilft Struktur zu schaffen. Code sauber zu organisieren. 

Sobald jede Klasse ein übergeordnetes Ziel hat, ist meist klar, wohin eine Methode gehört. Ob Du eine neue Klasse benötigst. Und so weiter.

Wie Du diesen Fehler vermeidest und das Single Responsibility Prinzip anwendest, zeige ich im eBook zu den Best-Practices.


3. Wiederholungen

Wiederholungen sind ein Folgeproblem von langen Methoden. Es fehlt an Übersicht. Dadurch passiert viel in einer Klasse. Du siehst die doppelten Stellen nicht.

Der wichtige Grundsatz aber lautet DRY: Don’t Repeat Yourself

Vielleicht so das heilige Gesetz unter Entwicklern. Das bekommst Du früh mit auf den Weg. Manche Dozenten sprechen dann gerne von “Programmierer sind faul”. So was halt.

Gemeint ist einfach: schreibe keine Logik zweimal. Absolut wichtig. Und doch passiert es immer wieder. 

Ein guter Weg aus dem Problem: Gewöhn Dir an Deinen Code regelmässig zu hinterfragen. Nicht nur die Klasse an der Du gerade arbeitest. Das große Ganze.

So behältst Du im Blick welcher Code existiert. Alles wirkt wie aus einem Guß. Bei Projekten über mehrere Manntage oder Wochen geht Dir solches Wissen verloren. 

Vorsichtig hinterfragen. Du darfst…

Keinen duplizierten Code übersehen

Achte nicht nur auf exakt gleiche Methoden. Doppelter Code versteckt sich in lange Methoden. 

Wiederholen sich vergleichbare Schleifen? Mit veränderten Namen? Gibt es nur minimalen Abweichungen?

Gerade das gilt es zu vermeiden. Der einfachste Weg das zu schaffen? Einfach kurze Methode schreiben! 

Und natürlich nicht…


4. Refactoring von eigenem Code vergessen

Refactoring ist nicht das Event in der Zukunft. Ein Termin mit einem Entwickler. Es ist ein fortlaufender Prozess.

Ich kenne keine Entwickler die komplette Projekte perfekt herunterschreiben. Autoren schreiben Bücher auch in mehreren Schritten.

Wichtigstes Ziel ist ein erster Entwurf.

Der ist NIE schön. Darum geht es nicht. Wichtiger ist Fortschritt.

Allerdings ist wichtig, was danach passiert. Du musst ihn überarbeiten. Verfeinern. Polieren. 

Jetzt kennst Du alle Zusammenhänge. Sobald der Entwurf steht hast Du einen Überblick. Wichtige Fragen beantworten:

  • Wo kannst Du vereinfachen? 
  • Wiederholt sich Code?
  • Musst Du Methoden überarbeiten?
  • Code in andere Klassen aufteilen?
  • Mit Interfaces verallgemeinern?

Anders gesagt: jetzt ist Zeit Code zu hinterfragen. Du kannst die Best Practices anwenden. Die Regeln für Clean Code.

Refactoring ist wichtig. Nur so kannst Du genialen Code ausliefern.

Aber bei allen Tipps in der Praxis… Du musst auch immer mal über den Tellerrand schauen. 

Ein Fehler ist das viele PHP-Entwickler …


5. Keine Design Patterns lernen

Kennst Du Design Patterns? Entwurfsmuster für Objektorientierung? Die sind unglaublich hilfreich.

Ich erinnere mich noch an meine Probleme mit Klassen & Co.

Syntax zu lernen war einfach. In meinem Regal über mir stehen immer noch die ersten PHP-Bücher. Mittlerweile verstaubt.

Aber… was nun damit anstellen? Wie strukturierst Du Projekte? Wozu ist die Syntax gut?

Stell Dir vor Du bekommst einen Hammer. Du lernst Nägel im Holz zu versenken (Syntax). Wie Du einen Stuhl oder einen Tisch baust, sagt Dir aber niemand.  

So ähnlich fühlt sich Objektorientierung an. Du haust ohne Plan erstmal oft daneben, manchmal auf die Finger.

So dauert es lange ein Gefühl für Architektur zu bekommen. 

Das lösen…

Entwurfsmuster

Viele Sprache nutzen Entwurfsmuster. Eigentlich vorgefertigte Lösungen für Szenarien im Code.

Wenn Du Dich damit befasst, erkennst Du schnell wie tolle Strukturen Objekte ermöglichen. 

Das öffnet Dir die Augen. 

Es sind zwar Muster für ganz bestimmte Anwendungsfälle. Aber Du schlägst beim Programmieren keinen Katalog mit Lösungen auf.

Du beim Programmieren einen…

Lösungskatalog im Hinterkopf haben

Programmieren ist in vielerlei Hinsicht wie Schreiben. Der kreative Teil holt Wissen aus dem Unterbewusstsein.

Und das musst Du trainieren. 

Wie im Fitnessstudio. Du trainierst um fit zu werden mit Gewichten. Nicht falls Dir beim Einkauf jemand im Supermarkt eine 30 Kilogramm Hantel gibt. 

Um besser zu Programmieren musst Du mehr Code schreiben. Neues Wissen finden und anwenden.

Such Dir Impulse. Schau Dir Code von anderen Projekten bei Github an. Lass Deinen Code bewerten.

Du lernst so etwas nicht durch Theorie. Die ist immer nur ein Anfang. Du musst Muster in Dein Unterbewusstsein bekommen. 

Die Designpatterns sind ein Start. Das sind sehr gut gemachte Beispiele mit sauberem Code.

Du musst nun nicht alle von A-Z durcharbeiten. Aber es ist gut wichtige zu kennen. Wenn Du sie implementierst, hilft Dir das mehr als sie in Framework zu verwenden:

Interessant sind:

  • Observer Pattern
  • Data Transfer Object
  • Factory
  • Model View Controller

Üben hilft Objekte mit neuen Augen zu betrachten.

Das waren die größten Fehler, die ich immer wieder beobachte. Jetzt kennst Du sie, und musst sie nicht mehr machen. 😉

Noch Zeit für ein kurzes…

Fazit

Versuch nicht krampfhaft Fehler zu vermeiden. Wenn Du jede Zeile hinterfragst schaffst Du nichts. Überarbeiten kannst Du jederzeit.

Aber…

Kommt es Dir vor, als würden sich Themen wiederholen? Gut! Es sind diese Grundlagen, die Dich zum Profi machen.

Du musst nicht drei Jahre lange Bücher mit 1000 Seiten durcharbeiten oder endlose Videokurse schauen. 

Du musst die Grundlagen umsetzen.

Einer der größten Trainer im American Football war Vince Lombardi. Sein Motto “brilliant at the basics” (beherrsche die Grundlagen). Kümmere Dich um die Grundlagen und der Erfolg kommt. 

Objektorientiertes PHP sofort verbessern: immer kurze Methoden schreiben

Ich habe es im eBook zu Best-Practices kurz erwähnt.

Es ist Best-Practice Deinen Code zu unterteilen. Wenn Du sauberen Code schreiben willst, ist das hier die einfachste Methode. Die Regel lässt sich ganz einfach anwenden.

Du musst einfach …

Kürzere Methoden schreiben

Kennst Du das Sprichwort “Code is poetry”? Da ist was dran.

Nur …

Ein “Meisterwerk” abzuliefern ist schwierig. Es muss alles stimmen:

  • Du musst Code übersichtlich strukturieren (Namespaces & Co)
  • Deine Klassen aufeinander abstimmen
  • Kannst Du das Projekt ohne Refactoring erweitern?
  • Kannst Du Klassen exakt in andere Projekte übernehmen?
  • Sind Deine Methoden übersichtlich?

Unter dem Strich musst Du Aufgaben bezahlbar lösen. Kunden zahlen nicht mehrere Manntage, wenn Du es in zwei Stunden lösen kannst.

Wenn unser Code Fehler erzeugt, bezahlt uns niemand, wenn wir sie beheben. Gewinnt unsaubere Arbeit die Überhand, drehen wir uns nur noch im Kreis

  • Kunden verlangen (zurecht), dass wir nachbessern
  • die Zeit fehlt für bezahlte Aufgaben

Außerdem stoßen wir auf Seiteneffekte. Du änderst Stelle A und Stelle B geht kaputt.

Mehrere Ideen lösen das Problem. Unsere Best-Practices findest Du im eBook:

Hier eine Low-Hanging Fruit, quasi ein …

Quickwin: Gestalte Methoden übersichtlich

Du musst übersichtliche Methoden schreiben. Der schnellste Weg zu sauberem Code.

Zu schwammig? Hier ein Beispiel.

Die Aufgabe: Du musst alle Benutzer aus der Datenbank lesen, ein Array erstellen und zurückgeben. Viele Einsteiger schreiben die Methode in der alles passiert.

  • sie lesen Daten aus der Datenbank
  • durchlaufen der Daten in einer Schleife
  • die Datenstruktur (ein Array) für den Benutzer erzeugen
  • die Informationen zum übergeordneten Array hinzufügen
  • Daten zurückgeben

Im Proof of Concept ist das OK. Es fällt beim Code Review durch. Es gibt gleich mehrere Probleme:

  • die Methode wird zu lang
  • die Logik lässt sich nicht wiederverwenden
  • ändert sich die Datenquelle (API statt Datenbank), musst Du Code editieren
  • das führt schnell zu Seiteneffekten und Du testet die Klasse erneut
  • wir leiten von Klassen ab und erben Methoden, um sie zu überschreiben.

Steht alles in einer Methode, musst Du die Methode in die Elternklasse kopieren um sie zu ändern. Inklusive der nicht geänderten Teile. 

Unsauber. Und schlecht bei Updates.

Gute Nachricht: Du kannst es verhindern. Lager jeden Schritt in Methoden aus.

Ein Beispiel

Im Beispiel geht es um eine Klasse von einem Magento Projekt. AJAX liest über eine Controller-Klasse (siehe MVC Pattern) Infos aus einem Produkt.

Rückgabewert ist in JSON formatiert.

Neben der Dependency Injection im Konstruktor (__construct()), ist der Code ab der execute()-Methode interessant:

<?php

namespace Custom\Description\Controller\Index;

use Magento\Catalog\Model\ProductRepository;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\View\Result\PageFactory;

class Index extends Action
{
    protected $_pageFactory;
    protected $_productRepository;
    protected $_jsonFactory;

    public function __construct(
        Context $context,
        JsonFactory $resultJsonFactory,
        ProductRepository $productRepository,
        PageFactory $pageFactory)
    {
        $this->_pageFactory = $pageFactory;
        $this->_productRepository = $productRepository;
        $this->_jsonFactory = $resultJsonFactory;
        return parent::__construct($context);
    }

    // (1)
    public function execute()
    {
        $result = $this->_jsonFactory->create();

        // (2)
        $id = (int)$this->getRequest()->getParam('product_id');
        if ($id) {
            // (5)
            return $result->setData([
                'description' => $this->getProductDescription($id)
            ]);

        } else {
            // (6)
            return $result->setData(['description' => false]);
        }
    }

    // (3)
    protected function getProductDescription($id)
    {
        $product = $this->getProductById($id);
        if ($product->getId()) {
            return $product->getDescription();
        } else {
            return false;
        }
    }

    // (4)
    protected function getProductById($id)
    {
        return $this->_productRepository->getById($id);
    }
}

Der Ablauf im Code:

  • der Einstieg ist die execute()-Methode (1)
  • der Controller liest eine Produkt ID aus der URL (2)
  • Produktbeschreibung wird gelesen (3)
  • dafür wird das Produkt geladen (4)
  • Rückgabe gefundener Daten (5) oder false (6)

Beachte: jeder Schritt geschieht in einer Methode:

  • execute(): der Einstiegspunkt
  • getProductDescription(): Wert zu einer ID zurückgeben
  • getProductById(): Produkt zu der ID laden / zurückgeben

Versuch Deine Methoden wie gezeigt zu unterteilen:

  • der Code wird übersichtlicher
  • Methoden können überlagert werden
  • Seiteneffekte nahezu ausgeschlossen

Beschränke Dich auf einen Aktion, bewerte den Rückgabewert. Über if und else kannst Du verzweigen. Solcher Code dokumentiert sich von selbst.

Fazit

Gewöhne Dir an Code zu strukturieren. Es führt zu übersichtlichen Klassen. Und Du kannst ab sofort damit loslegen.

Lange Methoden werden beim Code-Review nicht durchgewunken. In Feature-Branches in Git ist das OK. Bitte vor einem Pull-Request auflösen.

Wenn Du Hilfe beim Refactoring benötigst, melde Dich bei Jan.

Professionelle PHP-Entwicklung lernen

Hey! Es freut mich das Du hier bist.

Dieses Blog soll eine Ressource für professionelle PHP Entwicklung werden.

Jetzt gerade steht das Projekt noch ganz am Anfang.

Wir bauen aber unser Angebot aus.

Oh, apropos „wir“.

Der PHPGeek bin zwar ich, Jan. Aber hinter mir steht ein Team.

Tatsächlich ist sogar der Inhalt hier die Ressource, mit der in unserer Agentur neue Entwickler ausgebildet werden.

Wir nutzen Frameworks wie Symfony, arbeiten mit Shopware und Magento.

Professionelle Entwicklung ist da enorm wichtig.

Du bekommst hier nicht bunt zusammengewürfeltes Halbwissen.

Alles hier basiert auf über 16 Jahren PHP Erfahrung.

Und jetzt lade ich Dich einfach ein, auf der Seite zu stöbern und Dich auch gern für den Newsletter anzumelden.

In einem Jahr wünscht Du Dir, Du hättest heute begonnen.

Karen Lamb