$30 off During Our Annual Pro Sale. View Details »

DSLs As Teaching Tools

Ryan Cook
February 22, 2012

DSLs As Teaching Tools

Given at Boulder Ruby Group in February 2012. A presentation examining DSLs, what they might be teaching us or especially new programmers, and some common tactics or methodologies for creating them.

Ryan Cook

February 22, 2012
Tweet

Other Decks in Programming

Transcript

  1. DSLs
    Let Them Teach!

    View Slide

  2. WHAT IS A DSL?
    ● DSL = Domain Specific Language
    ● A lingual subset dedicated to a particular
    problem (domain) area
    ● Code that makes it easier to work on specific
    (types of) problems
    ● A specialized tool

    View Slide

  3. WHAT IS A DSL? (REDUX)
    talk "DSL" do | topic |
    topic.acronym true , [ "Domain" , "Specific" , "Language" ]
    topic.definition "A lingual subset dedicated to a particular problem (domain) area"
    topic.definition "Code that makes it easier to work on specific (types of) problems"
    topic.definition "A specialized tool"
    end

    View Slide

  4. WHAT IS THE GOAL OF A DSL?
    ● To provide a powerful and declarative
    abstraction around a specific set of
    underlying library/code functionality
    ● From @justicefries -- "Provide a means for
    developers to effectively communicate with
    each other and domain experts in a domain."

    View Slide

  5. POP CULTURE
    ● Code Academy and Code Year
    ○ Founder Sims - "Programming is the new literacy"
    ○ http://bit.ly/wO7UP3
    ● "Well understood problems lend themselves
    to DSLs"
    ○ http://bit.ly/wCqFKk
    ● "Human beings, as tool makers, can create
    things that amplify our ability"
    ○ Steve Jobs (1980) re: Scientific American study about inter-species
    locomotive efficiency
    ○ http://bit.ly/wE6HyH

    View Slide

  6. POP CULTURE
    ● "On the contrary, the best way to teach
    someone to code is within a meaningful
    context, where they are given an existing
    solution and guided how to alter and
    customise it to their preferences or
    requirements, as often required in the “real
    world”."
    ○ Andy Young of Kernel Mag on "Coding For Success"
    ○ http://bit.ly/xGxDAn

    View Slide

  7. WHERE OH WHERE
    ● Rake
    ● Sinatra
    ● ActiveRecord

    View Slide

  8. RAKE
    ● A DSL for definining command line interface
    tasks in Ruby
    ● A ruby build tool

    View Slide

  9. RAKE
    $ cat Rakefile
    namespace :my_task_group do
    task :my_task do
    p "hello"
    end
    end
    $ rake my_task_group:my_task
    hello

    View Slide

  10. RAKE
    ● Understand that it's helpful to name
    command line tasks
    ● Understand that it's helpful to namespace
    similar command line tasks
    ● Understand that it's helpful to describe
    command line tasks

    View Slide

  11. SINATRA
    ● A DSL for HTTP application servers built on
    Rack

    View Slide

  12. SINATRA
    $ cat app.rb
    require "sinatra"
    get "/" { body "Hello World!" }
    $ ruby app.rb &> /dev/null &
    $ curl 0.0.0.0:4567
    Hello World!
    (Who can spot the syntax error?)

    View Slide

  13. SINATRA
    $ cat app.rb
    require "sinatra"
    get("/") { body "Hello World!" }
    $ ruby app.rb &> /dev/null &
    $ curl 0.0.0.0:4567
    Hello World!

    View Slide

  14. SINATRA
    ● Understand that HTTP servers have a set
    number of methods through which to
    communicate (GET, POST, etc.)
    ● Understand that you have access to certain
    things in an HTTP request
    ● Understand that there are specific ways to
    respond to HTTP requests (response codes)
    ● Understand that there are parts of an HTTP
    response that you can control to have the
    desired effect

    View Slide

  15. ACTIVERECORD
    ● ActiveRecord's class methods provide many
    different DSLs
    ● A DSL for object relationships
    ● A DSL for object data validations
    ● A DSL for object callbacks

    View Slide

  16. ACTIVERECORD
    class MyModel < ActiveRecord::Base
    belongs_to :my_other_model
    validates_presence_of :my_important_field
    after_save { p "Saved!" }
    end

    View Slide

  17. ACTIVERECORD
    ● Understand different ways that data can be
    related
    ● Understand the power behind callbacks and
    how they can help you manage your data
    ● Understand validations and how they can
    help you keep your data standardized

    View Slide

  18. OTHERS
    ● What other DSLs do you like?

    View Slide

  19. HOW CAN THEY TEACH
    ● DSLs teach by making it easier to
    understand how to accomplish a problem
    though programming
    ● They lower the barrier to entry
    ● Help introduce people to programming
    concepts at a more gradual pace
    ● Provide more output for less input

    View Slide

  20. EASY?
    ● Programming is not easy, but DSLs can
    make it easier
    ● People know problem domains, but they
    don't always know how to program
    ● DSLs puts programming in a language that
    people understand inherently

    View Slide

  21. BARRIERS TO ENTRY
    ● There are A LOT of them
    ● e.g. Syntax, development environment
    ● Remove some of them and you'll be helping
    someone

    View Slide

  22. EASE INTO IT
    ● Help make the landing into programming a
    little softer
    ● A little syntax and maybe a little logic and
    they're off!

    View Slide

  23. MORE FOR LESS
    ● By writing only a tidbit of expressive and
    declarative code, a user can have built
    something very powerful

    View Slide

  24. THE POINT
    ● DSLs can be teaching tools unintentionally
    ● Writing a ton of DSLs around the problems
    WE solve isn't necessarily helpful
    ● If people can be taught how to use DSLs
    then they're one step closer to being a
    programmer

    View Slide

  25. WHAT I REALIZED
    ● DSLs are already a powerful teaching tool
    ● They teach programming through use
    assuming you know, or are willing to learn,
    the domain
    ● What's hard about them are the barriers to
    entry

    View Slide

  26. HOW TO DIY
    ● 3 common methodologies
    ○ Naked
    ○ Proc passing
    ○ Class methods
    ● Think: Object Builder

    View Slide

  27. NAKED DSL
    ● Rake
    ● Add methods globally
    ○ http://bit.ly/wk51Xa

    View Slide

  28. NAKED DSL (RAKE)
    $ cat lib/rake/dsl_definition.rb
    module Rake
    module DSL
    ... ALL the code ...
    end
    end
    self.extend Rake::DSL

    View Slide

  29. NAKED DSL
    ● Eval in context
    ● Rackup
    ○ Rack::Builder
    ○ http://bit.ly/ylRd0z
    ● Capistrano
    ○ Capistrano::Configuration::Loading
    ○ http://bit.ly/xLwveX

    View Slide

  30. NAKED DSL (RACKUP)
    $ cat lib/rack/builder.rb
    module Rack
    class Builder
    def self.parse_file( config , opts = Server::Options.new )
    ... other code ...
    # cfgfile is the result of a File::read
    app = eval \
    "Rack::Builder.new {\n" + cfgfile + "\n}.to_app",
    TOPLEVEL_BINDING,
    config
    ... other code ...
    end
    end
    end

    View Slide

  31. NAKED DSL (CAPISTRANO)
    $ cat lib/capistrano/configuration/loading.rb
    module Capistrano; class Configuration
    module Loading; module ClassMethods
    def load( *params , &block )
    ... other code ...
    # options[ :string ] is the result of a File::read
    instance_eval options[:string] , options[:name] || ""
    ... other code ...
    end
    end; end
    end; end

    View Slide

  32. PROC PASSING DSL
    ● Rails routes
    ○ Rails 2.3.X -- `map` object yielded to block directly
    ■ http://bit.ly/yU27AL
    ○ Rails 3.X.X -- proc `instance_exec`-ed behind the
    scenes on to `map` object
    ■ http://bit.ly/xGgvVg
    ■ http://bit.ly/zJkxd3

    View Slide

  33. PROC PASSING DSL (RAILS 2.3.X)
    $ cat actionpack/lib/action_controller/routing/route_set.rb
    module ActionController; module Routing
    class RouteSet
    class Mapper; ... other code ... end
    def draw
    yield Mapper.new( self )
    ... other code ...
    end
    end
    end; end

    View Slide

  34. PROC PASSING DSL (RAILS 3.X.X)
    $ cat actionpack/lib/action_dispatch/routing/route_set.rb
    module ActionDispatch; module Routing
    class RouteSet
    def draw( &block )
    eval_block block
    end
    def eval_block( block )
    Mapping.new( self ).instance_exec &block
    end
    end
    end; end

    View Slide

  35. CLASS METHODS
    ● ActiveRecord
    ○ http://bit.ly/xr34Qk

    View Slide

  36. CLASS METHODS (AR)
    $ cat activerecord/lib/active_record/associations.rb
    module ActiveRecord; module Associations
    module ClassMethods
    def belongs_to( name , options = {} )
    Builder::BelongsTo.new( self , name , options )
    end
    end
    end; end

    View Slide

  37. TIPS
    ● `Class.new`
    ● `const_get` and `const_set`
    ● `class_variable_get` and
    `class_variable_set` as well as their instance
    variable counterparts
    ● `Forwardable` and `def_delegators`
    ● Defining things directly on the included class
    with `Module::included`

    View Slide

  38. PITFALLS
    ● Definition vs. execution scope
    ● What is `self`?

    View Slide

  39. IN CONCLUSION
    ● Create DSLs for non-programmers
    ● Remove barriers to entry
    ● When you're writing a DSL, think about
    building objects

    View Slide

  40. THE END
    Questions?
    Thank you!
    Links: http://bit.ly/cookrn_boulder_ruby_feb_12
    Ryan Cook
    [email protected]

    View Slide