Göttlicher Code (GOTTES Code)



"Göttlicher" Code ist ein hoch klingender Begriff, der wie eine gelbe Überschrift erscheinen mag, aber genau dieser Code wird diskutiert: Aus welchen Teilen besteht er und wie schreibt man ihn? Dies ist eine Geschichte über meine Bemühungen, sicherzustellen, dass Aufgaben nicht mit einer Codeüberprüfung mit dem Hinweis "All he * nya - redo" zurückgegeben werden.

Ich habe keine spezielle Ausbildung und musste das Programmieren in der Praxis durch Fehler, Schürfwunden und Blutergüsse lernen. Ich arbeitete ständig daran, die Qualität des geschriebenen Codes zu verbessern, und erarbeitete einige Regeln, nach denen er eingehalten werden sollte. Ich möchte sie teilen.

GOTTES Code - Akronym Akronym - Code, der gemäß den Prinzipien von Grasp, Object Calisthenics, Demeter's Law und Solid geschrieben wurde. Jemand, den sie alle kennen, jemand hat nur einige getroffen, aber wir werden jede Komponente des Akronyms betrachten. Ich habe mir nicht zum Ziel gesetzt, mich eingehend mit jeder Regelgruppe zu befassen, da diese im Internet schon oft behandelt wurde. Stattdessen biete ich einen Squeeze aus meiner eigenen Erfahrung an.

GRASP


Neun Vorlagen zum Zuweisen von Verantwortlichkeiten zu Klassen und Objekten. Zum leichteren Erinnern teile ich sie in zwei Untergruppen ein:

  1. In der ersten Untergruppe können wir Regeln unterscheiden, mit denen Sie Atommodule schreiben können, die gut getestet und modifiziert sind. Bei diesen Regeln geht es nicht so sehr um Verantwortung, sondern beispielsweise um die Eigenschaften von Modulen: schwache Kopplung, starke Haftung, Polymorphismus, Beständigkeit gegen Änderungen. Für mich überschreibe ich diese Regeln mit SOLID, mehr dazu im entsprechenden Teil.
  2. Die zweite Untergruppe besteht bereits aus klareren Vorlagen, die Aufschluss darüber geben, wer die Objekte erstellt („Ersteller“ - der Sammelbegriff für Factory-Muster), wie die Verbindung zwischen den Modulen (mithilfe der Muster „Controller“ und „Vermittler“) verringert werden kann und an wen sie delegiert werden sollen individuelle Verantwortlichkeiten (Informationsexperte) und was zu tun ist, wenn ich DDD und gleichzeitig niedrige Kopplung (reine Fiktion) liebe.

Lesen Sie hier mehr.

Objekt Calisthenics


Eine Reihe von Regeln für die Codeausführung, die dem CodeStyle-Code of Laws sehr ähnlich sind. Es gibt auch neun von ihnen. Ich werde über drei sprechen, denen ich in meiner täglichen Arbeit folgen möchte (leicht modifiziert), der Rest kann in der Originalquelle gelesen werden.

  1. Die Methodenlänge beträgt nicht mehr als 15 LOC, die Anzahl der Methoden in einer Klasse beträgt nicht mehr als 15, die Anzahl der Klassen in einem Namespace beträgt nicht mehr als 15. Unter dem Strich sind lange Codeblätter sehr schwer zu lesen und zu verstehen. Darüber hinaus sind lange Klassen und Methoden ein Signal für eine Verletzung von SRP (mehr dazu weiter unten).
  2. Maximal eine Verschachtelungsebene pro Methode.

    public function processItems(array items)
    {
         // 0
         foreach (items as item) {
              // 1
              for (i = 0; i < 5; i++) {
                   // 2
                   … process item 5 times …
              }
         }
    }

    item .

    public function processItems(array items)
    {
         // 0
         foreach (items as item) {
              // 1
              this.processItem(item);
         }
    }
     
    public function processItem(Item item)
    {
         // 0
         for (i = 0; i < 5; i++) {
              // 1
              … process item 5 times …
         }
    }

    -, — , , .
  3. else , .

    public function processSomeDto(SomeDtoClass dto)
    {
         if (predicat) {
              throw new Exception(‘predicat is failed’);
         } else {
              return this.dtoProcessor.process(dto);
         }
    }

    :

    public function processSomeDto(SomeDtoClass dto)
    {
         if (predicat) {
              throw new Exception(‘predicat is failed’);
         }
     
         return this.dtoProcessor.process(dto);
    }

, .


GRASP’a. , .



: B, . . :

  1. .
  2. , .
  3. .
  4. , .

. , . this.objectB.objectC.getSomeStuff() , , .

. -, . :

public function methodA()
{
     spawnedObject = this.factory.spawn();
     spawnedObject.performSomeStuff();
}

:

public function methodA()
{
     this.factory.spawn().performSomeStuff();
}

, - .

public function methodA()
{
     this.processor.process(this.factory.spawn());
}

: DTO/Entity. .

public function methodA(SomeDtoClass dto)
{
     dto.getAddress().getCity();
}

, , . , , , , getCity DTO Address dto.

SOLID


SRP, OCP, LSP, ISP, DIP — , .

SRP — . — , . High Cohesion GRASP’a.

: , — - (MVC). - - , SRP.

public function indexAction(RequestInterface request): ResponseInterface
{
     requestDto = this.requestTransformer.transform(request);
     responseDto = this.requestProcessor.process(requestDto);
 
     return this.responseTransformer.transform(responseDto);
}

- , , — . , , , , .

OCP — -. , , .

- , if/switch. , . . — . , .

resolver, .

final lass Resolver implements ResolverInterface
{
     private mapping;
 
     public function Resolver(array mapping)
     {
          this.mapping = mapping;
     }
 
     public function resolve(Item item)
     {
          return this.mapping[item.getType()].perform(item);
     }
}

, . : , final, abstract, .

LSP — . , .

:

  1. ( ).
  2. ( , , , ).
  3. ( ).
  4. , ( , , , ).

    class ParentClass
    {
         public function someMethod(string param1)
         {
              // some logic
         }
    }
    
    class ChildClass extends ParentClass
    {
         public function someMethod(string param1, string param2)
         {
              if (param1 == '') {
                   throw new ExtraException();
              }
    
              // some logic
         }
    }


someMethod ChildClass (param2), param1, . , ParentClass ChildClass.

ISP — . , . , , , , — , .

interface DuckInterface
{
     public function swim(): void;

     public function fly(): void;
}

class MallardDuck implements DuckInterface
{
     public function swim(): void
     {
          // some logic
     }

     public function fly(): void
     {
          // some logic
     }
}

class RubberDuck implements DuckInterface
{
     public function swim(): void
     {
          // some logic
     }

     public function fly(): void
     {
          // can't fly :(
     }
}

RubberDuck DuckInterface. , , , DuckInterface FlyableInterface SwimableInterface, .

DIP — . , , ( , ). new .

class DIPViolation
{
     public function badMethod()
     {
          someService = new SomeService(445, 'second params');
          // operations with someService
     }
}

- , . . :

class DIP
{
     private $service;

     public function DIP(SomeServiceInterface $someService)
     {
          $this->someService = $someService;
     }

     public function goodMethod()
     {
          // operations with someService
     }
}

, , , , «» . , . , , , «», , :)

Source: https://habr.com/ru/post/de414201/


All Articles