Your business. Your language.
Your code.
Stephan Hochdörfer, bitExpert AG
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
Your business. Your language. Your code.
Focus on core business values!
Your business. Your language. Your code.
Get rid of the "framework speak"!
Your business. Your language. Your code.
Trust the framework...
Your business. Your language. Your code.
...but understand the underlying technology!
Your business. Your language. Your code.
Build your own toolset...
Your business. Your language. Your code.
...but focus on communication first!
Your business. Your language. Your code.
Work as a team! (Customer included!)
What the customer really wanted?
Your business. Your language. Your code.
A common language
Your business. Your language. Your code.
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.
A common language: Key characteristic
Your business. Your language. Your code.
Identifiable domain
A common language: Key characteristic
Your business. Your language. Your code.
„Small language“
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)
Domain-specific language: Examples
Your business. Your language. Your code.
How does a domain-specific
language look like?
SELECT * from slides WHERE presentationId = 4711 ORDER BY
pageNo;
Domain-specific language: SQL
Your business. Your language. Your code.
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.
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.
{
"require": {
"silex/silex": "v1.0.0",
"zendframework/zend-mail": "2.1.5",
"monolog/monolog": "1.5.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.19",
"phing/phing": "2.5.0"
}
}
Domain-specific language: Composer
Your business. Your language. Your code.
Domain-specific language: Doctrine
Your business. Your language. Your code.
/** @Entity **/
class Slides
{
/**
* @OneToOne(targetEntity="Presentation")
* @JoinColumn(name="presentation_id",
* referencedColumnName="id")
**/
private $presentation;
// ...
}
/** @Entity **/
class Presentation
{
// ...
}
<?php
echo "I am a DSL, too!";
Domain-specific language: PHP
Your business. Your language. Your code.
Why using a DSL?
Your business. Your language. Your code.
Why using a DSL?
Your business. Your language. Your code.
Increase your own productivity
Why using a DSL?
Your business. Your language. Your code.
Increase in code quality
Why using a DSL?
Your business. Your language. Your code.
Ignore the implementation details,
focus on the domain aspects
Why using a DSL?
Your business. Your language. Your code.
$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.
DSL types: You have to decide
Your business. Your language. Your code.
DSL types: You have to decide
Your business. Your language. Your code.
Internal DSL
vs.
External DSL
DSL types: Internal DSL
Your business. Your language. Your code.
DSL types: Internal DSL
Your business. Your language. Your code.
Fluent API, Expression Builder,
Functions, Closures, Annotations
Internal DSL: The Fluent API
Your business. Your language. Your code.
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.
$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.
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;
}
// [...]
}
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;
}
// [...]
}
Internal DSL: Expression Builder
Your business. Your language. Your code.
Internal DSL: Expression Builder
Your business. Your language. Your code.
Provides a fluent interface
on top of an existing API.
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.
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.
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());
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;
}
// [...]
}
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.
Internal DSL: Functions
Your business. Your language. Your code.
Internal DSL: Functions
Your business. Your language. Your code.
Using a combination of function calls
as a sequence of statements.
Internal DSL: Functions
Your business. Your language. Your code.
$file = '/path/to/a/file.csv';
message();
from('foo@bar.org');
to('bar@foo.org');
subject('Hello');
body('Sample mail body.');
attachFile($file);
sendWith(new SmtpTransport());
Internal DSL: Nested Functions
Your business. Your language. Your code.
Internal DSL: Nested Functions
Your business. Your language. Your code.
Using nested function calls to reflect
the hirarchic nature of the language.
$file = '/path/to/a/file.csv';
message(
header(
from('foo@bar.org'),
to('bar@foo.org'),
subject('Hello')
),
body('Sample mail body.'),
attachments(
file($file)
),
sendWith(new SmtpTransport())
);
Internal DSL: Nested Functions
Your business. Your language. Your code.
$file = '/path/to/a/file.csv';
$file2 = '/path/to/a/file2.csv';
message(
header(
[
from('foo@bar.org'),
to('bar@foo.org'),
subject('Hello')
]
),
body('Sample mail body.'),
attachments(
[
file($file),
file($file2)
]
),
sendWith(new SmtpTransport())
);
Internal DSL: Nested Functions (Improved)
Your business. Your language. Your code.
Internal DSL: Closure
Your business. Your language. Your code.
Internal DSL: Closure
Your business. Your language. Your code.
A function or reference to a function
together with a referencing environment.
$fname = '/path/to/a/file.csv';
$fname2 = '/path/to/a/file2.csv';
$msg = new MailMessageBuilder();
$msg->header(function($header){
$header->from('foo@bar.org')
->to('bar@foo.org')
->subject('Hello');
})
->body('Sample mail body.')
->attach(function($file){
$file->setContent(file_get_contents($fname)
->setFilename(basename($fname);
})
->attach(function($file){
$file->setContent(file_get_contents($fname2)
->setFilename(basename($fname2);
})
->sendWith(new SmtpTransport());
Internal DSL: Closure
Your business. Your language. Your code.
Internal DSL: Annotations
Your business. Your language. Your code.
Internal DSL: Annotations
Your business. Your language. Your code.
"An annotation is metadata
attached to your code."
(Rafael Dohms)
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
{
// ...
}
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.
class MyCustomController {
// [...]
/**
* @Allow(roles="ROLE_ADMIN")
*/
public function adminAction() {
// proceed with main logic...
}
}
Internal DSL: Annotations
Your business. Your language. Your code.
External DSL
Your business. Your language. Your code.
External DSL
Your business. Your language. Your code.
External DSLs provide a
greater syntactic freedom
External DSL: Language development
Your business. Your language. Your code.
Code generation
Your business. Your language. Your code.
Code generation
Your business. Your language. Your code.
From DSL to „code“ ;)
Code generation
Your business. Your language. Your code.
Template Generation
vs.
Transformer Generation
Code generation: Template Generation
Your business. Your language. Your code.
<?php
class [className] {
protected $service;
public function __construct([serviceType] $service) {
$this->service = $service;
}
}
Code generation: Transformer Generation
Your business. Your language. Your code.
<?php
renderPageHeader();
renderMenubar();
renderProducts();
renderFooter();
Output driven approach:
Code generation: Transformer Generation
Your business. Your language. Your code.
<?php
foreach($products as $product) {
renderName($product);
renderImage($product);
renderPrice($product);
}
Input driven approach:
Internal DSL vs. External DSL
Your business. Your language. Your code.
What to choose?
Problems with DSLs
Your business. Your language. Your code.
Problems with DSLs
Your business. Your language. Your code.
Yet-Another-Language-To-Learn
syndrome
Problems with DSLs
Your business. Your language. Your code.
Depending on the DSL complexity
creating a language can be cost intense
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)
Recommended books
Your business. Your language. Your code.
Thank you!
http://joind.in/8640
Credits
http://robonthemoon.wordpress.com/2009/11/24/what-the-customer-really-wanted-–-happ
y-thanksgiving/

Your Business. Your Language. Your Code - dpc13

  • 1.
    Your business. Yourlanguage. Your code. Stephan Hochdörfer, bitExpert AG
  • 2.
    Your business. Yourlanguage. Your code. About me  Stephan Hochdörfer  Head of IT at bitExpert AG, Germany  enjoying PHP since 1999  S.Hochdoerfer@bitExpert.de  @shochdoerfer
  • 3.
    Your business. Yourlanguage. Your code. Focus on core business values!
  • 4.
    Your business. Yourlanguage. Your code. Get rid of the "framework speak"!
  • 5.
    Your business. Yourlanguage. Your code. Trust the framework...
  • 6.
    Your business. Yourlanguage. Your code. ...but understand the underlying technology!
  • 7.
    Your business. Yourlanguage. Your code. Build your own toolset...
  • 8.
    Your business. Yourlanguage. Your code. ...but focus on communication first!
  • 9.
    Your business. Yourlanguage. Your code. Work as a team! (Customer included!)
  • 10.
    What the customerreally wanted? Your business. Your language. Your code.
  • 11.
    A common language Yourbusiness. Your language. Your code.
  • 12.
    A common language Yourbusiness. 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 Yourbusiness. Your language. Your code. "[…] I do think that the greatest potential benefit of DSLs comes when business people participate [...]" (Martin Fowler)
  • 16.
    Domain-specific language: Examples Yourbusiness. Your language. Your code. How does a domain-specific language look like?
  • 17.
    SELECT * fromslides WHERE presentationId = 4711 ORDER BY pageNo; Domain-specific language: SQL Your business. Your language. Your code.
  • 18.
    Feature: Serve coffee Inorder 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.
  • 20.
    { "require": { "silex/silex": "v1.0.0", "zendframework/zend-mail":"2.1.5", "monolog/monolog": "1.5.0" }, "require-dev": { "phpunit/phpunit": "3.7.19", "phing/phing": "2.5.0" } } Domain-specific language: Composer Your business. Your language. Your code.
  • 21.
    Domain-specific language: Doctrine Yourbusiness. Your language. Your code. /** @Entity **/ class Slides { /** * @OneToOne(targetEntity="Presentation") * @JoinColumn(name="presentation_id", * referencedColumnName="id") **/ private $presentation; // ... } /** @Entity **/ class Presentation { // ... }
  • 22.
  • 23.
    Why using aDSL? Your business. Your language. Your code.
  • 24.
    Why using aDSL? Your business. Your language. Your code. Increase your own productivity
  • 25.
    Why using aDSL? Your business. Your language. Your code. Increase in code quality
  • 26.
    Why using aDSL? Your business. Your language. Your code. Ignore the implementation details, focus on the domain aspects
  • 27.
    Why using aDSL? 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: Youhave to decide Your business. Your language. Your code.
  • 30.
    DSL types: Youhave to decide Your business. Your language. Your code. Internal DSL vs. External DSL
  • 31.
    DSL types: InternalDSL Your business. Your language. Your code.
  • 32.
    DSL types: InternalDSL Your business. Your language. Your code. Fluent API, Expression Builder, Functions, Closures, Annotations
  • 33.
    Internal DSL: TheFluent API Your business. Your language. Your code.
  • 34.
    Internal DSL: TheFluent 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: TheFluent 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: TheFluent 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; } // [...] }
  • 38.
    Internal DSL: ExpressionBuilder Your business. Your language. Your code.
  • 39.
    Internal DSL: ExpressionBuilder Your business. Your language. Your code. Provides a fluent interface on top of an existing API.
  • 40.
    class MimeMessage { publicfunction 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: ExpressionBuilder 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: ExpressionBuilder (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.
  • 45.
    Internal DSL: Functions Yourbusiness. Your language. Your code.
  • 46.
    Internal DSL: Functions Yourbusiness. Your language. Your code. Using a combination of function calls as a sequence of statements.
  • 47.
    Internal DSL: Functions Yourbusiness. Your language. Your code. $file = '/path/to/a/file.csv'; message(); from('foo@bar.org'); to('bar@foo.org'); subject('Hello'); body('Sample mail body.'); attachFile($file); sendWith(new SmtpTransport());
  • 48.
    Internal DSL: NestedFunctions Your business. Your language. Your code.
  • 49.
    Internal DSL: NestedFunctions Your business. Your language. Your code. Using nested function calls to reflect the hirarchic nature of the language.
  • 50.
    $file = '/path/to/a/file.csv'; message( header( from('foo@bar.org'), to('bar@foo.org'), subject('Hello') ), body('Samplemail body.'), attachments( file($file) ), sendWith(new SmtpTransport()) ); Internal DSL: Nested Functions Your business. Your language. Your code.
  • 51.
    $file = '/path/to/a/file.csv'; $file2= '/path/to/a/file2.csv'; message( header( [ from('foo@bar.org'), to('bar@foo.org'), subject('Hello') ] ), body('Sample mail body.'), attachments( [ file($file), file($file2) ] ), sendWith(new SmtpTransport()) ); Internal DSL: Nested Functions (Improved) Your business. Your language. Your code.
  • 52.
    Internal DSL: Closure Yourbusiness. Your language. Your code.
  • 53.
    Internal DSL: Closure Yourbusiness. Your language. Your code. A function or reference to a function together with a referencing environment.
  • 54.
    $fname = '/path/to/a/file.csv'; $fname2= '/path/to/a/file2.csv'; $msg = new MailMessageBuilder(); $msg->header(function($header){ $header->from('foo@bar.org') ->to('bar@foo.org') ->subject('Hello'); }) ->body('Sample mail body.') ->attach(function($file){ $file->setContent(file_get_contents($fname) ->setFilename(basename($fname); }) ->attach(function($file){ $file->setContent(file_get_contents($fname2) ->setFilename(basename($fname2); }) ->sendWith(new SmtpTransport()); Internal DSL: Closure Your business. Your language. Your code.
  • 55.
    Internal DSL: Annotations Yourbusiness. Your language. Your code.
  • 56.
    Internal DSL: Annotations Yourbusiness. Your language. Your code. "An annotation is metadata attached to your code." (Rafael Dohms)
  • 57.
    Internal DSL: Annotations Yourbusiness. 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.
  • 60.
    External DSL Your business.Your language. Your code.
  • 61.
    External DSL Your business.Your language. Your code. External DSLs provide a greater syntactic freedom
  • 62.
    External DSL: Languagedevelopment Your business. Your language. Your code.
  • 63.
    Code generation Your business.Your language. Your code.
  • 64.
    Code generation Your business.Your language. Your code. From DSL to „code“ ;)
  • 65.
    Code generation Your business.Your language. Your code. Template Generation vs. Transformer Generation
  • 66.
    Code generation: TemplateGeneration Your business. Your language. Your code. <?php class [className] { protected $service; public function __construct([serviceType] $service) { $this->service = $service; } }
  • 67.
    Code generation: TransformerGeneration Your business. Your language. Your code. <?php renderPageHeader(); renderMenubar(); renderProducts(); renderFooter(); Output driven approach:
  • 68.
    Code generation: TransformerGeneration 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?
  • 70.
    Problems with DSLs Yourbusiness. Your language. Your code.
  • 71.
    Problems with DSLs Yourbusiness. Your language. Your code. Yet-Another-Language-To-Learn syndrome
  • 72.
    Problems with DSLs Yourbusiness. 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)
  • 74.
    Recommended books Your business.Your language. Your code.
  • 75.
  • 76.
  • 77.