Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.
Domain Specific Languages
Escreva menos e entenda mais com DSLs desacopladas
By /Leonardo Tumadjian @tumadjian
Sobre mim:
Formado em Análise e Desenvolvimento de Sistemas
Programador PHP desde 2009
Instrutor desde 2012
Nas horas vaga...
Antes de começarmos:
Contribua com sua comunidade mais próxima, se tiver um
tempo ;)
Como contribuir?
Aviso!
O conteúdo desta palestra tem o intuito de ilustrar como as
DSLs podem facilitar a usabilidade de seu código, porém...
Referências
Alinhamento
API comando-consulta: componente ou biblioteca
ex: BrowserKit, SwiftMailer, Dispatcher, etc..
Linguagem de pro...
O que é?
“A computer programming language of limited
expressiveness focused on a particular
domain.” ―Martin Fowler
Quando usar?
Tipos de DSLs
Externas
Internas
Bancadas(Workbenches)
DSLs Externas
route
  path         /myblog/{pageId}/{commentId}
  controller   Myblog::commentsAction
  assert       pageI...
DSLs Externas
// Without the External DSL
require __DIR__ . '/vendor/autoload.php';
use SymfonyComponentRoutingRoute;
$app...
DSLs Externas Agenda
Agenda
    Appointment Dentist
        date 2016­01­15
            from 17:00
            to 18:00
  ...
DSLs Externas
Case de sucesso de uso de DSL externa, o Behat
Scenario: List 2 files in a directory
  Given I am in a direc...
DSLs Externas
// Generated class by behat command
class FeatureContext extends BehatContext
{
    private $output;
    // ...
DSLs Internas
// Without Internal DSL
$o1 = new Order();
$customer­>addOrder($o1);
$line1 = new OrderLine(6, Product::find...
Symfony Validation
use SymfonyComponentValidatorValidation;
use SymfonyComponentValidatorConstraints as Assert;
$constrain...
DSLs Internas
use DSLPALDSLValidator;
$fluent = new DSLValidator;
$errors = $fluent­>length(5, 20)
                 ­>notB...
Symfony Validation
use SymfonyComponentValidatorValidation;
use SymfonyComponentValidatorConstraints as Assert;
$constrain...
DSLs Internas
use DSLPALDSLValidator;
$fluent = new DSLValidator;
$constraints = $fluent­>collection([
    'nome'  =>  $fl...
DSLs Internas
use DSLPALValidatorFactory as dsl;
$const = dsl::collection([
    'nome' => dsl::type('string')
            ...
Cases de sucesso:
Respect Validator: http://respect.github.io/Validation/
// Use Respect/Validation!
use RespectValidation...
Annotations
/**
 * @ManyToMany(targetEntity="Group", inversedBy="features")
 * @JoinTable(name="user_groups",
 *      join...
Como programar DSLs?
Sugestão de workflow
Algumas reflexões:
1. Seu Modelo Semantico é complexo?
2. Se sim, você deve saber usá-lo muito bem
3. Evite retornar objet...
Construindo DSL de Agendamento
// API Comando­consulta Calendar
use CalendarAgenda;
use CalendarAppointment;
$agenda = new...
Como ficará a DSL
// DSL for Calendar
use CalendarBuilder;
$builder = Builder::make();
$builder
    ­>add('Dentist')
     ...
O construtor
namespace Calendar;
// Construtor de Expressões / Desacoplar a DSL
class Builder
{
    /**
     * @var Agenda...
Os métodos
    // ... Inside Class Builder
    public function add($name)
    {
        $this­>agenda­>addAppointment(Appo...
Retorna o objeto Agenda já configurado
    // ... Inside Class Builder
    public function getAgenda()
    {
        // Cl...
Problemas com DSLs
1. Cacofonia de linguagem
2. Custo de construção
3. Linguagem de gueto
4. Abstração restrita
5. Difícil...
Outros exemplos
// Sequência de funções
car('Maverik');
    engine('V8');
        cylinders('3,535');
        filter('Mons...
Outros exemplos
// Fecho aninhado ­ Closures
$carBuilder­>make(function ($car, $engine, $torque) {
    $car­>name = 'Maver...
Atenção!
Tomem muito cuidado para que isso não
aconteça com vocês
That's all folks!
Espero que tenham gostado, dúvidas?
Obrigado!
Meus contatos
About me: https://about.me/leonardotumadjian
Email me: tumadjian@gmail.com
Twitter: @tumadjian
Exemplos no G...
Prochain SlideShare
Chargement dans…5
×

Escreva menos e entenda mais com DSLs desacopladas

961 vues

Publié le

Palestra sobre DSLs Domain Specific Languages

Publié dans : Technologie

Escreva menos e entenda mais com DSLs desacopladas

  1. 1. Domain Specific Languages Escreva menos e entenda mais com DSLs desacopladas By /Leonardo Tumadjian @tumadjian
  2. 2. Sobre mim: Formado em Análise e Desenvolvimento de Sistemas Programador PHP desde 2009 Instrutor desde 2012 Nas horas vagas: Gamer, Biker, Shooter, Guitarrista Evangelista da comunidade PHPSP Víciado em séries estranhas!
  3. 3. Antes de começarmos: Contribua com sua comunidade mais próxima, se tiver um tempo ;) Como contribuir?
  4. 4. Aviso! O conteúdo desta palestra tem o intuito de ilustrar como as DSLs podem facilitar a usabilidade de seu código, porém devemos ter em mente que são específicos os casos, e que devem ser analisados com muita cautela.
  5. 5. Referências
  6. 6. Alinhamento API comando-consulta: componente ou biblioteca ex: BrowserKit, SwiftMailer, Dispatcher, etc.. Linguagem de propósito geral: PHP, Java, C++, Ruby Modelo Semântico: Modelo de objetos ou estrutura de dados
  7. 7. O que é? “A computer programming language of limited expressiveness focused on a particular domain.” ―Martin Fowler
  8. 8. Quando usar?
  9. 9. Tipos de DSLs Externas Internas Bancadas(Workbenches)
  10. 10. DSLs Externas route   path         /myblog/{pageId}/{commentId}   controller   Myblog::commentsAction   assert       pageId: "d+", commentId: "d+"   request      GET end route   path         /myblog/joinin   controller   Myblog::processForm   request      POST end
  11. 11. DSLs Externas // Without the External DSL require __DIR__ . '/vendor/autoload.php'; use SymfonyComponentRoutingRoute; $app = new SilexApplication(); $route1 = new Route('/myblog/{pageId}/{commentId}'); $route1­>setDefault('_controller', 'Myblog::commentsAction'); $route1­>setMethods(['GET']); $route1­>setRequirement('pageId', 'd+'); $route1­>setRequirement('commentId', 'd+'); $app['routes']­>add('route1', $route1); $route2 = new Route('/myblog/joinin'); $route2­>setDefault('_controller', 'Myblog::processForm'); $route2­>setMethods(['POST']); $app['routes']­>add('route2', $route2); $app­>run();
  12. 12. DSLs Externas Agenda Agenda     Appointment Dentist         date 2016­01­15             from 17:00             to 18:00     Appointment Dinner at Tiffani`s         date 2016­12­25             from 17:00             to 18:00 EndAgenda
  13. 13. DSLs Externas Case de sucesso de uso de DSL externa, o Behat Scenario: List 2 files in a directory   Given I am in a directory "test"   And I have a file named "foo"   And I have a file named "bar"   When I run "ls"   Then I should get:     """     bar     foo     """ Usabilidade: Scenario: Some description of the scenario   Given [some context]   When [some event]   Then [outcome]
  14. 14. DSLs Externas // Generated class by behat command class FeatureContext extends BehatContext {     private $output;     // ...     /** @Given /^I am in a directory "([^"]*)"$/ */     public function iAmInADirectory($dir)     {         if (!file_exists($dir)) {             mkdir($dir);         }         chdir($dir);     }     /** @Given /^I have a file named "([^"]*)"$/ */     public function iHaveAFileNamed($file)     {         touch($file);     }     // ... }
  15. 15. DSLs Internas // Without Internal DSL $o1 = new Order(); $customer­>addOrder($o1); $line1 = new OrderLine(6, Product::find('TAL')); $o1­>addLine($line1); $line2 = new OrderLine(5, Product::find('HPK')); $o1­>addLine($line2); $line3 = new OrderLine(3, Product::find('LGV')); $o1­>addLine($line3); $line2­>setSkippable(true); $o1­>setRush(true); // With Internal DSL $customer­>newOrder()     ­>with(6, 'TAL')     ­>with(5, 'HPK')­>skippable()     ­>with(3, 'LGV')     ­>priorityRush(); Font by Cal Evans: http://devzone.zend.com/777/fluent-interfaces-in-php/
  16. 16. Symfony Validation use SymfonyComponentValidatorValidation; use SymfonyComponentValidatorConstraints as Assert; $constraint = [     new AssertLength([         'min' => 5,         'max' => 20     ]),     new AssertNotBlank(),     new AssertEmail() ]; $validator = Validation::createValidator(); $errors = $validator­>validate('teste@gmail.com', $constraint);
  17. 17. DSLs Internas use DSLPALDSLValidator; $fluent = new DSLValidator; $errors = $fluent­>length(5, 20)                  ­>notBlank()                  ­>email()                  ­>validate('teste@teste.com');
  18. 18. Symfony Validation use SymfonyComponentValidatorValidation; use SymfonyComponentValidatorConstraints as Assert; $constraints = new AssertCollection([     'nome' => [         new AssertType('string'),         new AssertLength(['min' => 5, 'max' => 10])     ],     'email' => [         new AssertEmail()     ],     'sexo' => new AssertOptional([         new AssertNotBlank(),         new AssertChoice(['M', 'F'])     ]) ]); $validator = Validation::createValidator(); $res = $validator­>validate([     'nome' => 'Leonardo',     'email' => 'teste@teste.com',     'sexo' => 'N' ], $constraints);
  19. 19. DSLs Internas use DSLPALDSLValidator; $fluent = new DSLValidator; $constraints = $fluent­>collection([     'nome'  =>  $fluent                   ­>type('string')                   ­>length(5, 10)                 ­>end(),     'email' =>  $fluent                   ­>email()                 ­>end(),     'sexo'  =>  $fluent                   ­>notBlank()                   ­>choice(['M', 'F'])                   ­>optional()                 ­>end() ]); $res = $constraints­>validate([     'nome' => 'Leonardo',     'email' => 'teste@teste.com',     'sexo' => 'N' ]);
  20. 20. DSLs Internas use DSLPALValidatorFactory as dsl; $const = dsl::collection([     'nome' => dsl::type('string')                  ­>length(5, 10),     'email' => dsl::email(),     'sexo' => dsl::notBlank()                  ­>choice(['M', 'F'])                  ­>optional() ]); $erros = $const­>validate([     'nome' => 'Leonardo',     'email' => 'teste@teste.com',     'sexo' => 'N' ]);
  21. 21. Cases de sucesso: Respect Validator: http://respect.github.io/Validation/ // Use Respect/Validation! use RespectValidationValidator as v; $res = v::numeric()          ­>positive()          ­>between(1, 255)          ­>validate(180); Mockery: http://docs.mockery.io public function testGetsAverageTemperatureFromThreeServiceReadings() {     $service = m::mock('service');     $service­>shouldReceive('readTemp')             ­>times(3)             ­>andReturn(10, 12, 14);     $temperature = new Temperature($service);     $this­>assertEquals(12, $temperature­>average()); }
  22. 22. Annotations /**  * @ManyToMany(targetEntity="Group", inversedBy="features")  * @JoinTable(name="user_groups",  *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},  *      inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id  *      )  */ private $groups; /**  * Inverse Side  *  * @ManyToMany(targetEntity="User", mappedBy="groups")  */ private $features;
  23. 23. Como programar DSLs?
  24. 24. Sugestão de workflow
  25. 25. Algumas reflexões: 1. Seu Modelo Semantico é complexo? 2. Se sim, você deve saber usá-lo muito bem 3. Evite retornar objetos diferentes do modelo DSL 4. Lance sempre exceções detalhando os erros 5. Contexto completo para a execução 6. Sua DSL deve ser TODA documentada 7. Simplifique sempre, evite nome de métodos complexos 8. DSLs não são feitas só de encadeamento de métodos
  26. 26. Construindo DSL de Agendamento // API Comando­consulta Calendar use CalendarAgenda; use CalendarAppointment; $agenda = new Agenda; $appoint = Appointment::create(); $appoint­>setAppointment('Dentist'); $appoint­>setDate(15, 01, 2016); $appoint­>setFrom('17:00'); $appoint­>setTo('18:00'); $agenda­>addAppointment($appoint); $appoint = Appointment::create(); $appoint­>setAppointment('Dinner at Tiffani`s'); $appoint­>setDate(25, 12, 2015); $appoint­>setFrom('18:00'); $appoint­>setTo('01:00'); $agenda­>addAppointment($appoint);
  27. 27. Como ficará a DSL // DSL for Calendar use CalendarBuilder; $builder = Builder::make(); $builder     ­>add('Dentist')         ­>on(1, 15, 2016)         ­>from('17:00')         ­>to('18:00')     ­>add('Dinner at Tiffani`s')         ­>on(12, 25, 2015)         ­>from('18:00')         ­>to('01:00') ; $agenda = $builder­>getAgenda(); $user­>setAgenda($agenda);
  28. 28. O construtor namespace Calendar; // Construtor de Expressões / Desacoplar a DSL class Builder {     /**      * @var Agenda      */     protected $agenda; // keep all the appointments inside     public function __construct(Agenda $agenda)     {         $this­>agenda = $agenda;     }     public static function make()     {         return new self(new Agenda);     }     // ... }
  29. 29. Os métodos     // ... Inside Class Builder     public function add($name)     {         $this­>agenda­>addAppointment(Appointment::create());         $this­>current()­>setAppointmentName($name);         return $this;     }     public function on($month, $day, $year)     {         $this­>current()­>setDate($month, $day, $year);         return $this;     }     protected function current()     {         return $this­>agenda­>getCurrent();     }     // ...
  30. 30. Retorna o objeto Agenda já configurado     // ... Inside Class Builder     public function getAgenda()     {         // Clona o objeto para retornar         $agenda = clone $this­>agenda;         // Limpa o iterator da propriedade $agenda         $this­>agenda­>__construct();         return $agenda;     }     // ... Muito cuidado com referência X copia de objeto
  31. 31. Problemas com DSLs 1. Cacofonia de linguagem 2. Custo de construção 3. Linguagem de gueto 4. Abstração restrita 5. Difícil testar 6. Fácil fazer errado
  32. 32. Outros exemplos // Sequência de funções car('Maverik');     engine('V8');         cylinders('3,535');         filter('Monster');     color('green');     doors(2); // Função aninhada car(     'Maverik',     engine(         'V8',         cylinders('3,535'),         filter('Monster')     ),     color(         'green'     ),     doors(         2     ) );
  33. 33. Outros exemplos // Fecho aninhado ­ Closures $carBuilder­>make(function ($car, $engine, $torque) {     $car­>name = 'Maverik';     $car­>color = 'green';     $car­>doors = 2;     $car­>engine(function () use ($engine, $torque) {         $engine­>type = 'V8';         $engine­>cylinder = '3,535';         $engine­>torque(function () use ($torque) {             $torque­>initial = '1000rpm'; // not real             $torque­>final = '70000rpm'; // not real         });     }); });
  34. 34. Atenção! Tomem muito cuidado para que isso não aconteça com vocês
  35. 35. That's all folks! Espero que tenham gostado, dúvidas?
  36. 36. Obrigado!
  37. 37. Meus contatos About me: https://about.me/leonardotumadjian Email me: tumadjian@gmail.com Twitter: @tumadjian Exemplos no Github

×