Top Banner
MELHORANDO SUA API COM DSLS @augustohp
80

Melhorando sua API com DSLs

Apr 12, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Melhorando sua API com DSLs

MELHORANDO SUA API COM

DSLS@augustohp

Page 2: Melhorando sua API com DSLs

DOMAIN SPECIFIC LANGUAGE

Page 3: Melhorando sua API com DSLs

A SEGUIR, UMA

DSL

Page 4: Melhorando sua API com DSLs

VALIDAÇÃO

Page 5: Melhorando sua API com DSLs
Page 6: Melhorando sua API com DSLs

1 <?php 2 3 use Respect\Validation\Validator as v; 4 5 v::stringType() 6 ->exactLength(8) 7 ->contains("-") 8 ->contains("/^[A-Z]{3}/") 9 ->contains("/[0-9]{4}$/") 10 ->assert($something);

Page 7: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Validation\Rules; 4 5 use Respect\Validation\Rules as BaseRules; 6 7 class CarPlate extends BaseRules\AllOf 8 { 9 public function __construct() 10 { 11 $this->name = 'Brazilian car plate'; 12 13 parent::__construct( 14 new BaseRules\StringType(), 15 new ExactLength(8), 16 new BaseRule\Contains("-")->setName('Separator'), 17 new BaseRule\Contains("/^[A-Z]{3}/")->setName("Prefix") 18 new BaseRule\Contains("/^[0-9]{4}/")->setName("Sufix") 19 ); 20 } 21 }

Page 8: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Validation\Rules; 4 5 use Respect\Validation\Rules as BaseRules; 6 7 class CarPlate extends BaseRules\AllOf 8 { 9 public function __construct() 10 { 11 $this->name = 'Brazilian car plate'; 12 13 parent::__construct( 14 new BaseRules\StringType(), 15 new ExactLength(8), 16 new BaseRule\Contains("-")->setName('Separator'), 17 new BaseRule\Contains("/^[A-Z]{3}/")->setName("Prefix") 18 new BaseRule\Contains("/^[0-9]{4}/")->setName("Sufix") 19 ); 20 } 21 }

Page 9: Melhorando sua API com DSLs

1 <?php 2 3 // ... dentro de algum método de um Controller ... 4 5 Validation\Validator::arrayType() 6 ->key('driver_name', v::driverName()) 7 ->key('driver_birthdate', v::minimumAge(18)) 8 ->key( 9 'driver_car', v::arrayType( 10 v::key("model", v::carModel($this->get('model.vehicle'))), 11 v::key("assembler", v::carAssembler()), 12 v::key("year", v::maximumAge(5)), 13 v::key("plate", v::carPlate()) 14 ) 15 ) 16 ->key('license_number', v::driverLicense()) 17 ->key('taxi_permission', v::taxiPermissionNumber()) 18 ->key('address', v::address()) 19 ->assert($_POST);

Page 10: Melhorando sua API com DSLs

COMO CRIAR ISSO?

Page 11: Melhorando sua API com DSLs

1 <?php 2 3 namespace Respect\Validation; 4 5 class Validator 6 { 7 public function stringType() {} 8 public function contains($search) {} 9 public function assert($mixed) {} 10 }

Page 12: Melhorando sua API com DSLs
Page 13: Melhorando sua API com DSLs

1 <?php 2 3 namespace Respect\Validation; 4 5 interface Rule 6 { 7 public function isValid($mixed): bool; 8 }

Page 14: Melhorando sua API com DSLs

IMPLEMENTANDO UMA

REGRA

Page 15: Melhorando sua API com DSLs

1 <?php 2 3 namespace Respect\Validation\Rules; 4 5 use Respect\Validation; 6 7 class StringType implements Validation\Rule 8 { 9 public function isValid($mixed): bool 10 { 11 return is_string($mixed); 12 } 13 }

Page 16: Melhorando sua API com DSLs

3 namespace Respect\Validation\Rules; 4 5 use Respect\Validation; 6 7 class AllOf implements Validation\Rule 8 { 9 protected $rules = []; 10 17 public function __construct(Validation\Rule ...$rules) 18 { 19 $this->rules = $rules; 20 } 21 22 public function isValid($mixed): bool 23 { 24 foreach ($this->rules as $rule) { 25 if (false === $rule->isValid($mixed)) { 26 return false; 27 } 28 } 29 30 return true; 31 } 32 }

Page 17: Melhorando sua API com DSLs

INSTANCIANDO REGRAS

Page 18: Melhorando sua API com DSLs

1 <?php 2 3 $factory = new Respect\Validation\RuleFactory; 4 $rule = $factory->createInstance('StringType');

Page 19: Melhorando sua API com DSLs

1 <?php 2 3 namespace Respect\Validation; 4 5 class RuleFactory 6 { 7 public function createInstance($ruleName, array $args = []): Rule 8 { 9 $ruleNamespace = 'Respect\\Validation\\Rules\\'; 10 $className = $ruleNamespace . $rule; 11 $reflection = new ReflectionClass($className); 12 13 return $reflection->newInstanceArgs($args); 14 } 15 }

Page 20: Melhorando sua API com DSLs

PODEMOS TER

MENOS CÓDIGO ?

Page 21: Melhorando sua API com DSLs

1 <?php 2 3 namespace Respect\Validation; 4 5 class RuleFactory 6 { 7 public function __call($methodName, $methodArguments) 8 { 9 return $this->createInstance($methodName, $methodArguments); 10 } 11 12 public function createInstance($ruleName, array $args = []): Rule 13 { 14 /* ... */ 15 } 16 }

Page 22: Melhorando sua API com DSLs

1 <?php 2 3 $checkFor = new Respect\Validation\RuleFactory; 4 5 $isString = $checkFor->StringType(); 6 7 $isTwitterUserName = $checkFor->AllOf( 8 $checkFor->AlNum(), 9 $checkFor->NoWhitespace(), 10 $checkFor->Length(1, 15) 11 );

Page 23: Melhorando sua API com DSLs

PODEMOS TER

MENOS CÓDIGO ?

Page 24: Melhorando sua API com DSLs

3 namespace Respect\Validation; 4 5 class RuleFactory 6 { 7 private static $factory = null; 8 9 public static function getInstance() 10 { 11 if (is_null(self::$factory)) { 12 self::$factory = new static; 13 } 14 15 return self::$factory; 16 } 17 18 public static function __callStatic($methodName, $methodArguments) 19 { 20 $factory = self::getFactory(); 21 22 return $factory->createInstance($methodName, $methodArguments); 23 } 24 25 /* ... */ 26 }

Page 25: Melhorando sua API com DSLs

1 <?php 2 3 use Respect\Validation\RuleFactory as v; 4 5 $isTwitterUserName = v::AllOf( 6 v::AlNum(), 7 v::NoWhitespace(), 8 v::Length(1, 15) 9 );

Page 26: Melhorando sua API com DSLs
Page 27: Melhorando sua API com DSLs

@ANNOTATION

Page 28: Melhorando sua API com DSLs

O QUE TEMOS

Page 29: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Validation; 4 5 interface Rule 6 { 7 public function isValid($mixed): bool; 8 }

Page 30: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Validation\Rules; 4 5 use EasyTaxi\Validation; 6 use Respect\Validation\Validator as v; 7 8 class PlateValidator implements Rule 9 { 10 public function isValid($mixed): bool 11 { 12 return v::stringType() 13 ->exactLength(8) 14 ->contains("-") 15 ->contains("/^[A-Z]{3}/") 16 ->contains("/[0-9]{4}$/") 17 ->setName('Car plate') 18 ->validate($mixed); 19 } 20 }

Page 31: Melhorando sua API com DSLs

O QUE QUEREMOS

Page 32: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Driver; 4 5 class Car 6 { 7 /** 8 * @PlateValidator 9 */ 10 private $plate = ''; 11 12 public function __construct($plate) 13 { 14 $this->plate = $plate; 15 } 16 }

Page 33: Melhorando sua API com DSLs

1 <?php 2 3 use EasyTaxi\Annotation; 4 use EasyTaxi\Validation; 5 6 $filter = new Annotation\Filter(); 7 $factory = new Annotation\Factory($filter); 8 $validator = new Validation\Validator($factory); 9 $fusca = new Car('AAA-1111'); 10 11 $validator->annotations($fusca);

Page 34: Melhorando sua API com DSLs

FILTRANDO A PARTE

INTERESSANTE DE UM

COMENTÁRIO

Page 35: Melhorando sua API com DSLs

1 <?php 2 3 namespace EasyTaxi\Annotation; 4 5 class Filter 6 { 7 public function firstAnnotation($doc): string { 8 foreach ($this->breakLines($doc) as $line) { 9 if (false === $this->hasAnnotation($line)) { 10 continue; 11 } 12 13 return $this->filterName($line); 14 } 15 } 16 17 private function breakLines($doc): array { 18 return explode(PHP_EOL, $doc); 19 } 20 21 private function hasAnnotation($line): bool { 22 return false !== strpos($line, '@'); 23 } 24 25 private function filterName($line): string { 26 return trim(str_replace(['*', '/', '@'], '', $line)); 27 } 28 }

Page 36: Melhorando sua API com DSLs

CRIANDO REGRAS A PARTIR

DE UM COMENTÁRIO

Page 37: Melhorando sua API com DSLs

3 namespace EasyTaxi\Annotation; 4 5 class Factory 6 { 7 private $filter = null; 8 9 public function __construct(Filter $annotationFilter) 10 { 11 $this->filter = $annotationFilter; 12 } 13 14 public function createFromProperty($instance, $propertyName) 15 { 16 $object = new \ReflectionObject($instance); 17 $property = $object->getProperty($propertyName); 18 19 return $this->createInstanceFromComment($property->getDocComment()); 20 } 21 22 private function createInstanceFromComment($doc) 23 { 24 $annotationClass = $this->filter->firstAnnotation($doc); 25 $class = new \ReflectionClass($annotationClass); 26 27 return $class->newInstance(); 28 } 29 }

Page 38: Melhorando sua API com DSLs

JUNTANDO TUDO NUM

MONTINHO SÓ

Page 39: Melhorando sua API com DSLs

3 namespace EasyTaxi\Validation; 4 5 use EasyTaxi\Annotation; 6 7 class Validator 8 { 9 private $annotationFactory = null; 10 11 public function __construct(Annotation\Factory $factory) { 12 $this->annotationFactory = $factory; 13 } 14 15 public function annotations($object) { 16 $annotation = $this->annotationFactory; 17 $class = new \ReflectionObject($object); 18 $properties = $class->getProperties(); 19 foreach ($properties as $property) { 20 $propertyName = $property->getName(); 21 $rule = $annotation->createFromProperty($object, $propertyName); 22 if ($rule->isValid($object)) { 23 continue; 24 } 25 26 throw new \Exception("$propertyName is not valid."); 27 } 28 } 29 }

Page 40: Melhorando sua API com DSLs

1 <?php 2 3 use EasyTaxi\Annotation; 4 use EasyTaxi\Validation; 5 6 $filter = new Annotation\Filter(); 7 $factory = new Annotation\Factory($filter); 8 $validator = new Validation\Validator($factory); 9 $fusca = new Car('AAA-1111'); 10 11 $validator->annotation($fusca);

Page 41: Melhorando sua API com DSLs

OUTROS EXEMPLOS

Page 42: Melhorando sua API com DSLs

BEHAT

Page 43: Melhorando sua API com DSLs

COMPOSER

Page 44: Melhorando sua API com DSLs

PHING

Page 45: Melhorando sua API com DSLs

DQL

Page 46: Melhorando sua API com DSLs

PHPUNIT MOCK OBJECTS

Page 47: Melhorando sua API com DSLs

A VIDA DE UMA

DSL

Page 48: Melhorando sua API com DSLs

DOMÍNIO

Page 49: Melhorando sua API com DSLs

DSL INTERNADOMÍNIO

Page 50: Melhorando sua API com DSLs

DSL INTERNA

DSL EXTERNADOMÍNIO

Page 51: Melhorando sua API com DSLs

DSL INTERNA

DSL EXTERNA

Page 52: Melhorando sua API com DSLs

LIMITES DE UMA

DSL

Page 53: Melhorando sua API com DSLs
Page 54: Melhorando sua API com DSLs

AUTOMATIZAR TAREFAS

REPETITIVAS

Page 55: Melhorando sua API com DSLs

<TARGET NAME=“TEST”>

Page 56: Melhorando sua API com DSLs

<TARGET NAME=“DEPLOY”>

Page 57: Melhorando sua API com DSLs

<TARGET NAME=“BUILD”>

Page 58: Melhorando sua API com DSLs

<CONDITION>

Page 59: Melhorando sua API com DSLs

<CONDITION>

FAIL

Page 60: Melhorando sua API com DSLs

A SEGUIR, UMA

MENSAGEM

Page 61: Melhorando sua API com DSLs

1 <?php 2 3 use Respect\Validation\Validator as v; 4 5 v::stringType() 6 ->exactLength(8) 7 ->contains("-") 8 ->contains("/^[A-Z]{3}/") 9 ->contains("/[0-9]{4}$/") 10 ->assert($something);

Page 62: Melhorando sua API com DSLs

A VIDA DE UMA

MENSAGEM

Page 63: Melhorando sua API com DSLs

99% JAPA MAS

AQUELE 1% É ITALIANO

Page 64: Melhorando sua API com DSLs

PARA QUEM

VOCÊ ESTÁ FALANDO

Page 65: Melhorando sua API com DSLs

PARA QUEM

VOCÊ ESTÁ CODANDO

Page 66: Melhorando sua API com DSLs

UMA BOA

MENSAGEM TEM LIMITES

Page 67: Melhorando sua API com DSLs
Page 68: Melhorando sua API com DSLs

FAZ USO DE

CONHECIMENTO PRÉVIO

Page 69: Melhorando sua API com DSLs

FAZ USO DE UM

VOCABULÁRIO COMUM

Page 70: Melhorando sua API com DSLs

DOMÍNIOS

Page 71: Melhorando sua API com DSLs

QUE #%$!*&

SÃO

DSLS ?

Page 72: Melhorando sua API com DSLs
Page 73: Melhorando sua API com DSLs

DSLS SÃO

BOAS MENSAGENS

Page 74: Melhorando sua API com DSLs

DEPENDEM DE BONS

DOMÍNIOS

Page 75: Melhorando sua API com DSLs

SÃO MAIS ESPECÍFICAS

DO QUE LINGUAGENS GENÉRICAS

Page 76: Melhorando sua API com DSLs

POR ISSO COMUNICAM

MAIS COISAS

Page 77: Melhorando sua API com DSLs

DESENVOLVIMENTO É SOBRE

COMUNICAÇÃO

Page 78: Melhorando sua API com DSLs

PERGUNTAS?

Page 79: Melhorando sua API com DSLs

AGRADECIMENTOS

@NELSONSAR@IVONASCIMENTO

@ALGANET @ITEASYTAXI

Page 80: Melhorando sua API com DSLs

HTTP://BIT.LY/PHPX-DSLS