2. Your business. Your language. Your code.
About me
Stephan Hochdörfer
Head of IT at bitExpert AG, Germany
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
12. A common language
Your business. Your language. Your code.
A domain-specific language (DSL)
is a programming language designed
to be useful for a specific task.
13. A common language: Key characteristic
Your business. Your language. Your code.
Identifiable domain
14. A common language: Key characteristic
Your business. Your language. Your code.
„Small language“
15. A common language
Your business. Your language. Your code.
"[…] I do think that the greatest
potential benefit of DSLs comes when
business people participate [...]"
(Martin Fowler)
17. SELECT * from slides WHERE presentationId = 4711 ORDER BY
pageNo;
Domain-specific language: SQL
Your business. Your language. Your code.
18. Feature: Serve coffee
In order to earn money
Customers should be able to
buy coffee at all times
Scenario: Buy last coffee
Given there are 1 coffees left in the machine
And I have deposited 1 dollar
When I press the coffee button
Then I should be served a coffee
Domain-specific language: Gherkin
Your business. Your language. Your code.
19. package { 'screen' :
ensure => present,
}
include apache
apache::vhost { 'myapp.loc' :
docroot => '/srv/myapp.loc/webroot/'
}
host { 'myapp.loc':
ip => '127.0.1.1'
}
Domain-specific language: Puppet
Your business. Your language. Your code.
23. Why using a DSL?
Your business. Your language. Your code.
24. Why using a DSL?
Your business. Your language. Your code.
Increase your own productivity
25. Why using a DSL?
Your business. Your language. Your code.
Increase in code quality
26. Why using a DSL?
Your business. Your language. Your code.
Ignore the implementation details,
focus on the domain aspects
27. Why using a DSL?
Your business. Your language. Your code.
28. $file = '/path/to/a/file.csv';
$mimepart1 = new MimePart();
$mimepart1->setContent(file_get_contents($file));
$mimepart1->setFilename(basename($file));
$mimepart2 = new MimePart();
$mimepart2->setText('Sample mail body.');
$multipart = new MimeMultipart();
$multipart->addPart($mimepart1);
$multipart->addPart($mimepart2);
$message = new MimeMessage();
$message->setFrom('foo@bar.org');
$message->addTo('bar@foo.org');
$message->setSubject('Hello');
$message->setContent($multipart);
$transport = new MailTransport();
$transport->send($mail);
Why using a DSL? Non-DSL example
Your business. Your language. Your code.
29. DSL types: You have to decide
Your business. Your language. Your code.
30. DSL types: You have to decide
Your business. Your language. Your code.
Internal DSL
vs.
External DSL
32. DSL types: Internal DSL
Your business. Your language. Your code.
Fluent API, Expression Builder,
Functions, Closures, Annotations
33. Internal DSL: The Fluent API
Your business. Your language. Your code.
34. Internal DSL: The Fluent API
Your business. Your language. Your code.
A fluent interface is an implementation
of an object oriented API that aims to
provide for more readable code.
35. $file = '/path/to/a/file.csv';
$msg = new MailMessage();
$msg->from('foo@bar.org')
->to('bar@foo.org')
->subject('Hello')
->body('Sample mail body.')
->attachFile($file)
->sendWith(new SmtpTransport());
Internal DSL: The Fluent API
Your business. Your language. Your code.
36. Internal DSL: The Fluent API
Your business. Your language. Your code.
class MailMessage {
protected $from;
protected $to;
public function from($from) {
$this->from = $from;
return $this;
}
public function to($to) {
$this->to = $to;
return $this;
}
// [...]
}
37. Internal DSL: The Fluent API
Your business. Your language. Your code.
class MailMessage {
protected $from;
protected $to;
public function from($from) {
$this->from = $from;
return $this;
}
public function to($to) {
$this->to = $to;
return $this;
}
// [...]
}
39. Internal DSL: Expression Builder
Your business. Your language. Your code.
Provides a fluent interface
on top of an existing API.
40. class MimeMessage {
public function setFrom($from) {
}
public function addTo($to) {
}
public function setSubject($subject) {
}
public function setContent(MimeMultipart $content) {
}
}
Internal DSL: Expression Builder
Your business. Your language. Your code.
41. class MailBuilder {
protected $msg;
protected $multipart;
public function __construct() {
$this->msg = new MimeMessage();
$this->multipart = new MimeMultipart();
}
public function from($from) {
$this->msg->setFrom($from);
return $this;
}
public function attachFile($file) {
$part = new MimePart();
$part->setContent(file_get_contents($file));
$part->setFilename(basename($file));
$this->multipart->addPart($part);
return $this;
}
// [...]
}
Internal DSL: Expression Builder
Your business. Your language. Your code.
42. Internal DSL: Expression Builder
Your business. Your language. Your code.
$file = '/path/to/a/file.csv';
$msg = new MailBuilder();
$msg->from('foo@bar.org')
->to('bar@foo.org')
->subject('Hello')
->body('Sample mail body.')
->attachFile($file)
->sendWith(new SmtpTransport());
43. Internal DSL: Expression Builder (Improved)
Your business. Your language. Your code.
class MailBuilder {
protected $msg;
protected $parts;
public function __construct() {
$this->msg = new MimeMessage();
$this->parts = array();
}
public function from($from) {
$this->msg->setFrom($from);
return $this;
}
public function attachFile($file) {
$builder = new PartBuilder($this);
$this->parts[] = $builder;
return $builder;
}
// [...]
}
44. class PartBuilder {
protected $part;
public function __construct() {
$this->part = new MimePart();
}
public function content($content) {
$this->part->setContent($content);
return $this;
}
public function filename($filename) {
$this->part->setFilename($filename);
return $this;
}
// [...]
}
Internal DSL: Expression Builder (Improved)
Your business. Your language. Your code.
49. Internal DSL: Nested Functions
Your business. Your language. Your code.
Using nested function calls to reflect
the hirarchic nature of the language.
56. Internal DSL: Annotations
Your business. Your language. Your code.
"An annotation is metadata
attached to your code."
(Rafael Dohms)
57. Internal DSL: Annotations
Your business. Your language. Your code.
/** @Entity **/
class Slides
{
/**
* @OneToOne(targetEntity="Presentation")
* @JoinColumn(name="presentation_id",
* referencedColumnName="id")
**/
private $presentation;
// ...
}
/** @Entity **/
class Presentation
{
// ...
}
58. class MyCustomController {
// [...]
public function adminAction() {
$user = $this->authService->getLoggedInUser();
if(!$user->hasRole('ROLE_ADMIN')) {
throw new AccessDeniedException();
}
// proceed with main logic...
}
}
Internal DSL: Annotations
Your business. Your language. Your code.
59. class MyCustomController {
// [...]
/**
* @Allow(roles="ROLE_ADMIN")
*/
public function adminAction() {
// proceed with main logic...
}
}
Internal DSL: Annotations
Your business. Your language. Your code.
66. Code generation: Template Generation
Your business. Your language. Your code.
<?php
class [className] {
protected $service;
public function __construct([serviceType] $service) {
$this->service = $service;
}
}
67. Code generation: Transformer Generation
Your business. Your language. Your code.
<?php
renderPageHeader();
renderMenubar();
renderProducts();
renderFooter();
Output driven approach:
68. Code generation: Transformer Generation
Your business. Your language. Your code.
<?php
foreach($products as $product) {
renderName($product);
renderImage($product);
renderPrice($product);
}
Input driven approach:
69. Internal DSL vs. External DSL
Your business. Your language. Your code.
What to choose?
71. Problems with DSLs
Your business. Your language. Your code.
Yet-Another-Language-To-Learn
syndrome
72. Problems with DSLs
Your business. Your language. Your code.
Depending on the DSL complexity
creating a language can be cost intense
73. Famous final words ;)
Your business. Your language. Your code.
"Any fool can write code that a
computer can understand. Good
programmers write code that
humans can understand."
(Martin Fowler)