Allumeddd

 @vibby0

Allumeddd

Fabrique
d’Allumettes
Industrielle
Ligériennes

Rencontrer
un métier

Représenter le réel :

User Story

En tant que receptionnaire,
Je receptionne un tronc
Afin d’en préparer le débitage

Spécifier

namespace spec;

use PhpSpec\ObjectBehavior;

class ReceptionisteSpec extends ObjectBehavior
{
    function it_receptionne_tronc()
    {
    	$tronc = new Tronc('542kg');        
    	$this->receptionnerTronc($tronc)->shouldReturn($etiquette);
    }
}

Encore trop old-school

Le cas d’usage

namespace App\Scierie\Application\UseCase\ReceptionerUnTronc;

use App\Scierie\Domain\Depository\TroncDepository;

class ReceptionerUnTroncHandler
{
    function __construct(
        private readonly TroncDepository $troncDepository;
    ) {}

    function __invoke(ReceptionerUnTroncInput $input)
    {
    	$tronc = new Tronc(
            masse: $input->masse,
            essence: $input->essence
        );
        $this->troncDepository->store($tronc);
        
    	return new Etiquette($tronc);
    }
}

Qu’est ce qu’on fait ?

Entrée

Qu’est ce qu’on donne ?

namespace App\Scierie\Application\
    UseCase\ReceptionerUnTronc;
    
use Symfony\Component\Validator\Constraints;
use App\Scierie\Application\Asserts;

class ReceptionerUnTroncInput
{
    function __construct(    
        #[Constraints\NotBlank]
        #[Asserts\IsMasse]
        public string $masse,
        #[Constraints\NotBlank]
        #[Asserts\IsEssence]
        public string $essence,
    ) {}
}

Objet métier

C’est quoi ce truc ?

namespace App\Scierie\Domain\Entity;
    
use App\Scierie\Application\Asserts;
use Ramsey\Uuid\Uuid;

#[Asserts\MasseMinimumParEssence]
class Tronc
{
    public readonly Uuid $id;
    
    function __construct(    
        private Masse $masse,
        private Essence $essence,
    ) {
    	$this->id = Uuid::uuid4();
    }
    
    function refendre(
        EpaisseurDeCoupe $epaisseur
    ): Planche {
        […]
    }
}

Value object

Une propriété à forte valeur

namespace App\Scierie\Domain\ValueObject;

use Symfony\Component\Validator\Constraints;

class Masse
{
    function __construct(    
        #[Constraints\Positive]
        public readonly int $value,
        public readonly UniteMasse $unite,
    ) {
    }
}

Enum UniteMasse
{
    case Kilogramme;
    case Tonne;
    case Livre;
}

Interfaces

Se connecter au monde

namespace App\Scierie\Domain\Depository;

interface TroncDepository
{
    function store(Tronc $tronc): void;
    
    function update(Tronc $tronc): void;    
    
    function marquerCommeSecs(\DateTime $date);
}

interface TroncRepository
{
    function findById(Uuid $id): Tronc;
    
    function findByMasseMinimum(
      Tronc $tronc,
      Masse $masse,
    ): \ArrayObject;    
}

Point Archi

- src
  - Scierie
    - Application
      - UseCase
         - ReceptionnerTronc
         - RefendreTronc
      - Asserts
    - Domain
      - Entity
      - ValueObject
      - Depository
      - Repository

- Franglais d’ubiquitous langage

- La doc ? Quelle doc ?

- Je fais pas du MVC ! (ou si ?)

- Tests fonctionnels

Modélisation

- Holistique et Étendue

- Sous-domaines

- Objectiver le métier

 

C’est fini ?

On entre par où ?

- Site web backend

- API pour frontend

- Appli mobile

- Ligne de commande

- Objet connecté

Avec Symfony

Côté gauche

namespace App\Scierie\Infrastructure\Controller;

class NewTroncController extends AbstractController
{
    public function __invoke(
    	Request $request,
        ReceptionerUnTroncHandler $handler,
    ) {
    	$input = new ReceptionerUnTroncInput(
            masse: $request->get('masse'),
            essence: $request->get('essence'),
        );
        $etiquette = $handler($input);
        
        return $this->render(
          'view.html.twig',
          ['etiquette' => $etiquette]
        );
    }
}

Avec Symfony

Côté droit

namespace App\Scierie\Domain\Depository;

interface TroncDepo implements TroncDepository
{
    function __construct(
    	private EntityManager $em,
    	private ElasticSearchIndexer $es,
    ){}

    function store(Tronc $tronc)
    {
    	$this->em->persist($tronc);
    	$this->em->flush();
    	$this->es->index($tronc);
    }
}

Doctrine

namespace App\Scierie\Infrastructure\Doctrine\Type;

use Doctrine\DBAL\Types\ArrayType;
use App\Scierie\Domain\ValueObject\Masse;

class voMasseType extends ArrayType
{
    function convertToPHPValue($value): mixed
    {
    	return new Masse($value['value'], $value['unite']);
    }

    function convertToDatabaseValue($value): array
    {
        return [
        	'value' => $value->value,
        	'unite' => $value->unite,
        ];
    }
}
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="…">
  <entity name="App\Scierie\Domain\Entity\Tronc">
    <field name="id" type="string" length="32" />
    <field name="masse" type="vo_masse" length="16" />
    <field name="essence" type="enum_essence" length="16" />
  </entity>
</doctrine-mapping>

Because I’m API

Api-Platform

App\Scierie\Domain\Entity\Tronc:
  attributes:
    order:
      dateArrivee: ASC
  collectionOperations:
    get:
      method: GET
      security: is_granted('ROLE_USER')
      output: App\Forfait\Application\Output\Etiquette
    post:
      method: POST
      path: /reception-tronc
      security: is_granted('ROLE_RECEPTIONISTE')
      input: App\Scierie\Application\UseCase\ReceptionerUnTroncInput
      output: App\Forfait\Application\Output\Etiquette
      messenger: input
  itemOperations:
    get:
      method: GET
      security: is_granted('ROLE_USER')
      output: App\Forfait\Application\Output\Etiquette

Jusqu’où ?

  • ERP, CRM, GED, CMS ?
  • Identifier le spécifique
  • Pour quels projets ?
  • Dette technique

Au service

  • Approche globale
  • Se méfier du besoin exprimé
  • Se concentrer sur la valeur

Allumeddd

 @vibby0

Merci

deck

By vibby

deck

  • 134