Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

PHP Experience 2016 - [Palestra] Melhorando a comunicação da API através de DSL

393 views

Published on

Augusto Pascutti, Software Engineer no Easy Taxi, fez a palestra "Melhorando a comunicação da API através de DSL", no PHP Experience 2016.

O iMasters PHP Experience 2016 aconteceu nos dias 21 e 22 de Março de 2015, no Hotel Tivoli em São Paulo-SP
http://phpexperience2016.imasters.com.br/

Published in: Education
  • Be the first to comment

PHP Experience 2016 - [Palestra] Melhorando a comunicação da API através de DSL

  1. 1. MELHORANDO SUA API COM DSLS@augustohp
  2. 2. DOMAIN SPECIFIC LANGUAGE
  3. 3. A SEGUIR, UMA DSL
  4. 4. VALIDAÇÃO
  5. 5. 1 <?php 2 3 use RespectValidationValidator as v; 4 5 v::stringType() 6 ->exactLength(8) 7 ->contains("-") 8 ->contains("/^[A-Z]{3}/") 9 ->contains("/[0-9]{4}$/") 10 ->assert($something);
  6. 6. 1 <?php 2 3 namespace EasyTaxiValidationRules; 4 5 use RespectValidationRules as BaseRules; 6 7 class CarPlate extends BaseRulesAllOf 8 { 9 public function __construct() 10 { 11 $this->name = 'Brazilian car plate'; 12 13 parent::__construct( 14 new BaseRulesStringType(), 15 new ExactLength(8), 16 new BaseRuleContains("-")->setName('Separator'), 17 new BaseRuleContains("/^[A-Z]{3}/")->setName("Prefix") 18 new BaseRuleContains("/^[0-9]{4}/")->setName("Sufix") 19 ); 20 } 21 }
  7. 7. 1 <?php 2 3 namespace EasyTaxiValidationRules; 4 5 use RespectValidationRules as BaseRules; 6 7 class CarPlate extends BaseRulesAllOf 8 { 9 public function __construct() 10 { 11 $this->name = 'Brazilian car plate'; 12 13 parent::__construct( 14 new BaseRulesStringType(), 15 new ExactLength(8), 16 new BaseRuleContains("-")->setName('Separator'), 17 new BaseRuleContains("/^[A-Z]{3}/")->setName("Prefix") 18 new BaseRuleContains("/^[0-9]{4}/")->setName("Sufix") 19 ); 20 } 21 }
  8. 8. 1 <?php 2 3 // ... dentro de algum método de um Controller ... 4 5 ValidationValidator::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);
  9. 9. COMO CRIAR ISSO?
  10. 10. 1 <?php 2 3 namespace RespectValidation; 4 5 class Validator 6 { 7 public function stringType() {} 8 public function contains($search) {} 9 public function assert($mixed) {} 10 }
  11. 11. 1 <?php 2 3 namespace RespectValidation; 4 5 interface Rule 6 { 7 public function isValid($mixed): bool; 8 }
  12. 12. IMPLEMENTANDO UMA REGRA
  13. 13. 1 <?php 2 3 namespace RespectValidationRules; 4 5 use RespectValidation; 6 7 class StringType implements ValidationRule 8 { 9 public function isValid($mixed): bool 10 { 11 return is_string($mixed); 12 } 13 }
  14. 14. 3 namespace RespectValidationRules; 4 5 use RespectValidation; 6 7 class AllOf implements ValidationRule 8 { 9 protected $rules = []; 10 17 public function __construct(ValidationRule ...$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 }
  15. 15. INSTANCIANDO REGRAS
  16. 16. 1 <?php 2 3 $factory = new RespectValidationRuleFactory; 4 $rule = $factory->createInstance('StringType');
  17. 17. 1 <?php 2 3 namespace RespectValidation; 4 5 class RuleFactory 6 { 7 public function createInstance($ruleName, array $args = []): Rule 8 { 9 $ruleNamespace = 'RespectValidationRules'; 10 $className = $ruleNamespace . $rule; 11 $reflection = new ReflectionClass($className); 12 13 return $reflection->newInstanceArgs($args); 14 } 15 }
  18. 18. PODEMOS TER MENOS CÓDIGO ?
  19. 19. 1 <?php 2 3 namespace RespectValidation; 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 }
  20. 20. 1 <?php 2 3 $checkFor = new RespectValidationRuleFactory; 4 5 $isString = $checkFor->StringType(); 6 7 $isTwitterUserName = $checkFor->AllOf( 8 $checkFor->AlNum(), 9 $checkFor->NoWhitespace(), 10 $checkFor->Length(1, 15) 11 );
  21. 21. PODEMOS TER MENOS CÓDIGO ?
  22. 22. 3 namespace RespectValidation; 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 }
  23. 23. 1 <?php 2 3 use RespectValidationRuleFactory as v; 4 5 $isTwitterUserName = v::AllOf( 6 v::AlNum(), 7 v::NoWhitespace(), 8 v::Length(1, 15) 9 );
  24. 24. @ANNOTATION
  25. 25. O QUE TEMOS
  26. 26. 1 <?php 2 3 namespace EasyTaxiValidation; 4 5 interface Rule 6 { 7 public function isValid($mixed): bool; 8 }
  27. 27. 1 <?php 2 3 namespace EasyTaxiValidationRules; 4 5 use EasyTaxiValidation; 6 use RespectValidationValidator 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 }
  28. 28. O QUE QUEREMOS
  29. 29. 1 <?php 2 3 namespace EasyTaxiDriver; 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 }
  30. 30. 1 <?php 2 3 use EasyTaxiAnnotation; 4 use EasyTaxiValidation; 5 6 $filter = new AnnotationFilter(); 7 $factory = new AnnotationFactory($filter); 8 $validator = new ValidationValidator($factory); 9 $fusca = new Car('AAA-1111'); 10 11 $validator->annotations($fusca);
  31. 31. FILTRANDO A PARTE INTERESSANTE DE UM COMENTÁRIO
  32. 32. 1 <?php 2 3 namespace EasyTaxiAnnotation; 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 }
  33. 33. CRIANDO REGRAS A PARTIR DE UM COMENTÁRIO
  34. 34. 3 namespace EasyTaxiAnnotation; 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 }
  35. 35. JUNTANDO TUDO NUM MONTINHO SÓ
  36. 36. 3 namespace EasyTaxiValidation; 4 5 use EasyTaxiAnnotation; 6 7 class Validator 8 { 9 private $annotationFactory = null; 10 11 public function __construct(AnnotationFactory $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 }
  37. 37. 1 <?php 2 3 use EasyTaxiAnnotation; 4 use EasyTaxiValidation; 5 6 $filter = new AnnotationFilter(); 7 $factory = new AnnotationFactory($filter); 8 $validator = new ValidationValidator($factory); 9 $fusca = new Car('AAA-1111'); 10 11 $validator->annotation($fusca);
  38. 38. OUTROS EXEMPLOS
  39. 39. BEHAT
  40. 40. COMPOSER
  41. 41. PHING
  42. 42. DQL
  43. 43. PHPUNIT MOCK OBJECTS
  44. 44. A VIDA DE UMA DSL
  45. 45. DOMÍNIO
  46. 46. DSL INTERNAO
  47. 47. DSL EXTERNA
  48. 48. LIMITES DE UMA DSL
  49. 49. AUTOMATIZAR TAREFAS REPETITIVAS
  50. 50. <TARGET NAME=“TEST”>
  51. 51. <TARGET NAME=“DEPLOY”>
  52. 52. <TARGET NAME=“BUILD”>
  53. 53. <CONDITION>
  54. 54. <CONDITION> FAIL
  55. 55. A SEGUIR, UMA MENSAGEM
  56. 56. 1 <?php 2 3 use RespectValidationValidator as v; 4 5 v::stringType() 6 ->exactLength(8) 7 ->contains("-") 8 ->contains("/^[A-Z]{3}/") 9 ->contains("/[0-9]{4}$/") 10 ->assert($something);
  57. 57. A VIDA DE UMA MENSAGEM
  58. 58. 99% JAPA MAS AQUELE 1% É ITALIANO
  59. 59. PARA QUEM VOCÊ ESTÁ FALANDO
  60. 60. PARA QUEM VOCÊ ESTÁ CODANDO
  61. 61. UMA BOA MENSAGEM TEM LIMITES
  62. 62. FAZ USO DE CONHECIMENTO PRÉVIO
  63. 63. FAZ USO DE UM VOCABULÁRIO COMUM
  64. 64. DOMÍNIOS
  65. 65. QUE #%$!*& SÃO DSLS ?
  66. 66. DSLS SÃO BOAS MENSAGENS
  67. 67. DEPENDEM DE BONS DOMÍNIOS
  68. 68. SÃO MAIS ESPECÍFICAS DO QUE LINGUAGENS GENÉRICAS
  69. 69. POR ISSO COMUNICAM MAIS COISAS
  70. 70. DESENVOLVIMENTO É SOBRE COMUNICAÇÃO
  71. 71. PERGUNTAS?
  72. 72. AGRADECIMENTOS @NELSONSAR @IVONASCIMENTO @ALGANET @ITEASYTAXI
  73. 73. HTTP://BIT.LY/PHPX-DSLS

×