Software organization

https://matiux.github.io/slides/software-organization

Matteo Galacci

Software architect & Back-end Developer

Github:  https://github.com/matiux

Slack GRUSP:  matiux

Email:  m.galacci@gmail.com

Linkedin: Matteo Galacci

  • Developer since 2000
  • Consultant since 2008  
  • Software architect
  • Back-end developer
  • Domain Driven Design & Clean Code evangelist 
  • Member of PUG Romagna admins

Cos'è lo sviluppo software

  • Sviluppo software != Scrivere codice
  • Sviluppo software != Usare framework
  • Sviluppo software != Usare librerie

I Programmatori

non hanno "bisogno" di framework e/o librerie

Cos'è lo sviluppo software

Cosa vuol dire che  i programmatori non hanno "bisogno" di framework e/o librerie?

  • Programmare == risolvere problemi di business (dominio)
  • Risolvere problemi di business (dominio) != framework / librerie*

*Spesso introducono legami infrastrutturali che invece dovremmo procrastinare il più possibile. Più riusciamo a procrastinarli, più il nostro software è sulla buona strada.

Framework

Dominio

Software

Cos'è lo sviluppo software

ALCUNI ELEMENTI DI UN SOFTWARE

  • Avere le idee chiare sul dominio
  • Distinguere tra richieste di business (dominio) e aspetti tecnologici
  • Test
  • Pulizia del codice
  • Naming
  • Organizzazione del codice

Cos'è lo sviluppo software

AVERE LE IDEE CHIARE SUL DOMINIO

Tutto ciò che nel contesto aziendale è vero a prescindere dal software

Logiche e formule (di business - dominio)

Calcolare il costo di un'automobile

Carta, penna e calcolo il preventivo

Cos'è lo sviluppo software

ASPETTI DI DOMINIO E ASPETTI TECNOLOGICI

  • Entità preventivo
  • Salvataggio preventivo
  • Repositories
  • Form input
  • Riepilogo preventivo fatto
  • Transazioni numero preventivo
  • Invio preventivo
  • numero preventivo
  • Calcolo preventivo
  • Transazioni
  • Migrazioni
  • Command
  • Controller
  • Data fixtures
  • Eventi
  • Event Subscriber

Cos'è lo sviluppo software

ASPETTI DI DOMINIO E ASPETTI TECNOLOGICI

DOMINIO

INFRASTRUTTURA

Cos'è lo sviluppo software

ASPETTI DI DOMINIO E ASPETTI TECNOLOGICI

  • Entità preventivo *
  • Salvataggio preventivo
  • Repositories
  • Riepilogo preventivo fatto
  • Invio preventivo
  • Numero preventivo
  • Calcolo preventivo
  • Eventi
  • Salvataggio preventivo
  • Repositories
  • Form input
  • Riepilogo preventivo fatto
  • Transazione numero preventivo
  • Invio preventivo
  • Transazioni
  • Migrazioni
  • Command
  • Controller
  • Data fixtures
  • Event Subscriber

DOMINIO

INFRASTRUTTURA

Cos'è lo sviluppo software

TEST

  • Learning Test
  • TDD
  • Test unitari
  • Test di integrazione
  • Test end-to-end

I test non sono un optional, e non andrebbero fatti dopo aver scritto il codice, ma prima

Cos'è lo sviluppo software

PULIZIA DEL CODICE

  • Serve chiarezza e ordine.
  • Si legge dall'inizio alla fine. *
  • Ci sono grammatica, paragrafi e capitoli.

Scrivere codice è come scrivere un libro.

*Con qualche differenza per i programmi async

Cos'è lo sviluppo software

NAMING

*Un software che parla di infrastruttura, librerie e framework, avrà vita breve. In alcuni casi è voluto.

 Ogni parola in un libro è scelta con cognizione di causa, sulla base della grammatica e di ciò che si vuole esprimere.

I software, come i libri raccontano qualcosa;

raccontano le esigenze di business. *

Nomi delle variabili, delle cartelle, delle classi e dei namespace, vanno ugualmente scelti con cognizione di causa. Prendetevi del tempo!

Cos'è lo sviluppo software

NAMING

function calculate($a, $b)
{
    $res = $a - $b;

    return ($res / $b) * 100;
}
function getPercentageChange($oldNumber, $newNumber)
{
    $decreaseValue = $oldNumber - $newNumber;

    return ($decreaseValue / $oldNumber) * 100;
}
foreach($data => $key as $item)
{
    $this->repo->add($item);
    
    $this->names[] = $item->name();
}
foreach($people => $personId as $person)
{
    $this->people->add($person);
    
    $this->peopleNames[] = $person->name();
}
  • Usa nomi 1:1 con il dominio
  • Non scrivere inglese solo perché "i programmatori scrivono inglese"
  • Crea il tuo DSL
  • Pensa al software come a un libro

Un gatto

I PROGRAMMATORI WEB

Vogliamo essere utilizzatori o programmatori?

Si concentrano su framework o tecnologie, ma…

Spesso non conoscono la programmazione, perchè...

(Anti) Framework Driven Design

I framework rendono i programmatori pigri

I framework guidano le scelte e lo sviluppo del software

In ambito web, quanto detto sopra pare essere più accentuato

(Anti) Framework Driven Design

Essere allineati sull'utilizzo di un framework non è risolutivo per un software di qualità

Il framework se ne frega se competenze e conoscenze sono disallineate

Usare un framework non garantisce che tutti i membri del team rispettino uno standard

(Anti) Framework Driven Design

Se il framework va utilizzato in modo marginale, su cosa ci concentriamo?

PRINCIPI

  • Agnostici *
  • Tendenzialmente eterni **

* E' agnostico chi non prende posizione, evitando il  giudizio circa un problema, in quanto non se ne ha, o non se ne può avere, abbastanza conoscenza.

** Sempre sull'esempio dei libri, pensate alla scrittura; pietra, pergamena, carta, digitale

(Anti) Framework Driven Design

Se il framework va utilizzato in modo marginale, su cosa ci concentriamo?

PRINCIPI

  • Agnostici *
  • Tendenzialmente eterni **

* E' agnostico chi non prende posizione, evitando il  giudizio circa un problema, in quanto non se ne ha, o non se ne può avere, abbastanza conoscenza.

** Sempre sull'esempio dei libri, pensate alla scrittura; pietra, pergamena, carta, digitale

UN ALTRO GATTO

NAMING

* Phil Karlton - Sviluppatore Netscape

La difficoltà di cui parla non risiede nell'azione di “scrivere” un nome, una parola.

"There are only two hard things in Computer Science: cache invalidation and naming things." *

Sta piuttosto nel significato che, grazie a quel nome, vogliamo attribuire a una cosa.

NAMING

  • Book
  • Libro
  • BookRepository
  • LibroRepository
  • Libri
  • Libreria

Nella vita di tutti i giorni usiamo nomi per identificare oggetti, o per esprimere concetti. Ci viene spontaneo farlo e ci rende la vita semplice (a patto di conoscere la lingua in questione, l’italiano nel nostro caso). Lo facciamo quotidianamente, per farci comprendere da chi ci ascolta.

NAMING

class BookRepository
{
   public function save(Book $book): void
   {
      //...
   }
}

// Utilizzo il repository
$bookRepository->save($book);
class Libreria
{
   public function aggiungi(Libro $libro): void
   {
      //...
   }
}

// Utilizzo il repository
$libreria->aggiungi($libro);

NAMING

 Dal mondo DDD, Ubiquitous language

Il codice è ciò che scriviamo e che vogliamo sia comprensibile anche in futuro.

le cose alle quali dobbiamo dare nomi nel codice, sono le richieste di business (il dominio) che ci vengono fatte.

L’italiano è la nostra lingua di dominio

NAMING

Se un vostro collega vi spiega qualcosa su un software scritto in inglese, in che lingua lo fa?

Quando il committente, o il business ti da indicazioni sul software da sviluppare, parlandoti del dominio, in che lingua lo fa?

NAMING

// Doctrine's way
$results = $bookRepository->findByAuthor('Matteo Galacci');

foreach($results => $result)
{
	echo $result->author;
}
$libriTrovati = $libri->conAutore('Matteo Galacci');

foreach($libriTrovati => $libro)
{
	// Magari usiamo un Value Object (DDD)
	echo $libro->autore()->nome();
}

NAMING

interface BuildingInterface
{
  public function getFloors(): int
}

class Tower implements BuildingInterface
{
  public function getFloors(): int
  {
    return 34;
  }
}

NAMING

interface Edificio
{
  public function piani(): int
}

class Torre implements Edificio
{
  public function piani(): int
  {
    return 34;
  }
}

class CalcolaValoreEdificio
{
  public function execute(Edificio $edificio): float
  {
  }
  
  public function __invoke(Edificio $edificio): float
  {
  
  }
}

$calcolaValoreEdificio = new CalcolaValoreEdificio();

$torre = new Torre();
$valore = $calcolaValoreEdificio->execute($torre);
$valore = $calcolaValoreEdificio($torre);

NAMING

class Libro
{
  private function __construct(IdLibro $idLibro)
  {
    $this->idLibro = $idLibro;
  }

  public static function creaVuoto(IdLibro $idLibro): self
  {
    return new self($idLibro);
  }
   
  public static function crea(IdLibro $idLibro, Autore $autore): self
  {
    $libro = new self($idLibro);
    $libro->autore = $autre;
    return $libro;
  }
   
  public static function copiaDa(Libro $libroOriginale, IdLibro $idLibro): self
  {
    $libro = new self($idLibro);
    $libro->autore = $libroOriginale->autore();
    return $libro;
  }
  
  public function autore(): Autore {}
}

NAMING

  • Rendono il software incomprensibile, anche per l'autore
  • Tolgono valore al software; una variabile anonima non ha significato, non rappresenta alcun dominio
  • Aumentano il debito tecnico
  • Ci rendono programmatori irrispettosi nei confronti dei colleghi

Variabili come: $data, $result, $x, $y, $content, $foo, $bar

"Quando facciamo fatica a capire il codice altrui, non è scontato che il problema sia la nostra mancata conoscenza. Magari stiamo leggendo dei geroglifici."

cit. Io

gatto nel cocomero

codice italiano

* Questo principio non vale per una libreria, per un driver infrastrutturale.

Mi concentro sul dominio, e se il dominio è italiano, la modellazione del codice viene di conseguenza. *

  • Spesso i domini sono complicati
  • DDD nasce con l’intento di agevolare analisi e sviluppo di domini complicati

  • Uno dei building blocks del DDD è l’ubiquitous language, principio che ci suggerisce di dare importanza al linguaggio di dominio.

codice italiano

Se con il business tratto concetti italiani, e non solo a livello linguistico, ma anche a livello concettuale ("codice fiscale", legislazione, burocrazia), perché devo introdurre una complessità (la traduzione), quando grazie al DDD sto cercando di toglierne?

Organizzazione del codice

Scrivere un programma dovrebbe essere una ricerca spasmodica di perfezione.

Nome di una variabile

Architettura di alto livello

Ogni volta che veniamo a meno su questa ricerca:

  • Il nostro programma degrada
  • Accumuliamo debito tecnico
  • I nostri colleghi ci odieranno*

* Se lavorate da soli, odierete voi stessi

Organizzazione del codice

Nomi e concetti ben espressi danno consistenza al dominio

Nomi delle cartelle e organizzazione dei file non possono essere lasciati al caso

Organizzazione (GATTO) del codice

Organizzazione del codice

Propongono strutture che non enfatizzano il dominio

I framework fanno male all'organizzazione del codice (e non solo)

Colpa bilaterale

Il programmatore non studia

Il fw suggerisce la propria struttura

Organizzazione del codice

  • Pigrizia?
  • Cieca fiducia?

Ci si fida del framework pensando che il codice possa essere organizzato senza alcun criterio

Il "problema", capito fin dove il framework arriva, risiede nel programmatore.

Organizzazione del codice

SYMFONY 5

your-project/
├─ assets/
├─ bin/
│  └─ console
├─ config/
├─ public/
│  └─ index.php
├─ src/
│  └─ ...
├─ templates/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  ├─ log/
│  └─ ...
└─ vendor/
your_project/
├─ assets/
├─ bin/
│  └─ console
├─ config/
│  ├─ packages/
│  └─ services.yaml
└─ public/
│  ├─ build/
│  └─ index.php
├─ src/
│  ├─ Kernel.php
│  ├─ Command/
│  ├─ Controller/
│  ├─ DataFixtures/
│  ├─ Entity/
│  ├─ EventSubscriber/
│  ├─ Form/
│  ├─ Migrations/
│  ├─ Repository/
│  ├─ Security/
│  └─ Twig/
├─ templates/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  └─ log/
└─ vendor/

Organizzazione del codice

SYMFONY 5

  • Entità preventivo *
  • Salvataggio preventivo
  • Repositories
  • Riepilogo preventivo fatto
  • Invio preventivo
  • Numero preventivo
  • Calcolo preventivo
  • Eventi

DOMINIO

your_project/
├─ assets/
├─ bin/
│  └─ console
├─ config/
│  ├─ packages/
│  └─ services.yaml
└─ public/
│  ├─ build/
│  └─ index.php
├─ src/
│  ├─ Kernel.php
│  ├─ Command/
│  ├─ Controller/
│  ├─ DataFixtures/
│  ├─ Entity/
│  ├─ EventSubscriber/
│  ├─ Form/
│  ├─ Migrations/
│  ├─ Repository/
│  ├─ Security/
│  └─ Twig/
├─ templates/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  └─ log/
└─ vendor/

Organizzazione del codice

SYMFONY 5

  • Salvataggio preventivo
  • Repositories
  • Form input
  • Riepilogo preventivo fatto
  • Transazione numero preventivo
  • Invio preventivo
  • Transazioni
  • Migrazioni
  • Command
  • Controller
  • Data fixtures
  • Event Subscriber

INFRASTRUTTURA

your_project/
├─ assets/
├─ bin/
│  └─ console
├─ config/
│  ├─ packages/
│  └─ services.yaml
└─ public/
│  ├─ build/
│  └─ index.php
├─ src/
│  ├─ Kernel.php
│  ├─ Command/
│  ├─ Controller/
│  ├─ DataFixtures/
│  ├─ Entity/
│  ├─ EventSubscriber/
│  ├─ Form/
│  ├─ Migrations/
│  ├─ Repository/
│  ├─ Security/
│  └─ Twig/
├─ templates/
├─ tests/
├─ translations/
├─ var/
│  ├─ cache/
│  └─ log/
└─ vendor/

Organizzazione del codice

SYMFONY 5

Non voglio dire che Symfony "deve" dirci come organizzare il codice o come programmare, ma sta qui l'inghippo:

Non è compito del framework dirci cosa e come fare.

E' compito del programmatore studiare.

Organizzazione del codice

SYMFONY 5 + HEXAGONAL ARCHITECTURE

  • Dominio
  • Infrastruttura
  • Applicazione

Organizzazione del codice

SYMFONY 5 + Hexagonal Architecture

├── Assicurazione (Dominio)
│   └── CalcoloPreventivo (Sottodominio)
│       ├── Application
│       ├── Domain
│       └── Infrastructure
└── App
    ├── Data
    │   └── Migrations
    │       ├── Version20200521140651.php
    │       └── Version20200603103548.php
    └── Kernel.php

Organizzazione del codice

SYMFONY 5 + Hexagonal Architecture

├── Assicurazione (Dominio)
│   ├── CalcoloPreventivo (Sottodominio - BC)
│   │   ├── ListinoPrezzi (Modulo)
│   │   └── Preventivo (Modulo)
│   │       ├── Application
│   │       ├── Domain
│   │       │   
│   │       │   
│   │       │   
│   │       │   
│   │       │   
│   │       │  
│   │       │   
│   │       │   
│   │       │   
│   │       │       
│   │       └── Infrastructure
│   │   │   ├── Entity
│   │   │   │   ├── ListinoPrezzi (Modulo)
│   │   │   │   └── Preventivo (Modulo)
│   │   │   │       ├── Preventivo.php
│   │   │   │       ├── Preventivi.php
│   │   │   │       └── IdPreventivo.php
│   │   │   ├── Service
│   │   │   │   ├── ListinoPrezzi (Modulo)
│   │   │   │   └── Preventivo (Modulo)
│   │   │   │       ├── CreaPreventivo.php
│   │   │   │       └── CreaPreventivoRequest.php
│   │   │   └── ValueObject
│   │   │       └── Preventivo (Modulo)
│   │   │           └── NumeroPreventivo.php
├── Assicurazione (Dominio)
│   ├── CalcoloPreventivo (Sottodominio - BC)
│   │   ├── Application
│   │   ├── Domain
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │   
│   │   │       
│   │   │       
│   │   │          
│   │   └── Infrastructure
│   │       │   ├── Entity
│   │       │   │   ├── Preventivo.php
│   │       │   │   ├── Preventivi.php
│   │       │   │   └── IdPreventivo.php
│   │       │   ├── Service
│   │       │   │   ├── CreaPreventivo.php
│   │       │   │   └── CreaPreventivoRequest.php
│   │       │   └── ValueObject
│   │       │       └── NumeroPreventivo.php

Organizzazione del codice

SYMFONY 5 + Hexagonal Architecture

├── Assicurazione (Dominio)
│   ├── CalcoloPreventivo (Sottodominio BC)
│   │   └── Preventivo (Modulo)
    │   │   ├── Application
    │   │   ├── Domain
    │   │   └── Infrastructure
    │   │       ├── Communication
    │   │       │   └── Http
    │   │       │       └── Symfony
    │   │       │           └── Controller
    │   │       │               └── PreventivoController.php
    │   │       ├── Command
    │   │       │   └── Console
    │   │       │       └── Symfony
    │   │       │           └── FaQualcosaInShell.php
    │   │       └── Domain
    │   │           ├── Service
    │   │           │    └── TransactionalDomainService.php
    │   │           └── Doctrine
    │   │               ├── Entity
    │   │               │   ├── DoctrinePreventivi.php
    │   │               │   └── DoctrineIdPreventivo.php
    │   │               ├── Persistence
    │   │               │   └── Mapping
    │   │               │       ├── Entity.Preventivo.orm.xml
    │   │               │       ├── Entity.RiepilogoPreventivo.orm.xml
    │   │               │       └── ValueObject.NumeroPreventivo.orm.xml
    │   │               └── ValueObject
    │   │                   └── DoctrineNumeroPreventivo.php

Organizzazione del codice

SYMFONY 5 + Hexagonal Architecture

├── Assicurazione
│   ├── CalcoloPreventivo
│   │   └── Preventivo (Modulo)
    │   │   ├── Application
    │   │   │   ├── DataTransformer
    │   │   │   │   └── PreventivoToArrayDataTransformer.php
    │   │   │   └── Service
    │   │   │       └── TrovaPreventivo.php
    │   │   ├── Domain
    │   │   └── Infrastructure

Fine