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.
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
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
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."
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
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
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
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
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
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
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
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
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
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
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
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
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
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`