The first comment to make about DSLs is that like any good "next big thing" they've been about for ever. If you've ever used a library, framework or XML schema, you've come across a Domain Specific Language. If you've ever created a class, written a simple framework, created a custom tag or created some kind of configuration file format (whether XML or not), you've written a DSL. Even if you've never written a DSL for someone else, if you have broken your code down into reusable functions or method calls, you've created a set of languages in your application for providing layered levels of abstraction to make your code more maintainable and comprehensible, so congratulations - you're a language designer!
A Domain Specific Language is simply a collection of one or more concepts that can be used to express intent within a limited domain. Libraries, frameworks and XML schemas are all ways of expressing (and in the case of libraries and frameworks, implementing) Domain Specific Languages. If you're not sure what a DSL is, give Martin twenty five minutes and he'll make it really clear.
So, if everyone has been doing these things for ever, why bother with a new label? The most powerful tools a programmer has are the concepts that they use to think about solving problems. Generally programmers with more concepts are more likely to come up with better solutions to a wider range of problems as they have more tools in their toolkit (which is why it is worth learning about OO and functional programming even if you're not planning to write code in Java and Haskell any time soon). The problem as a programmer is that when you only have a hammer, every problem looks like a nail. This works fine until you come across a screw and suddenly your trusty hammer doesn't seem quite as useful as it used to.
What is your "hammer"? Do you reflexively use MG:U or Rails for web applications? Do you write lots of libraries? Do you think XML is the solution to every configuration problem? The fact is that each of these "hammers" is extremely powerful and it is quite possible that you work within a constrained domain where all you need is your hammer of choice, but by understanding about Domain Specific Languages, you can understand the trade offs your tools are making and you can roll your own tool if one of the prebuilt tools doesn't meet your needs.
Top Down or Bottom Up?
There are two broad ways to design DSLs - top down and bottom up. With a top down approach, you take words from the problem domain and focus on a good language for capturing unambiguous functional requirements without worrying about how you'll interpret the language or generate the code once you have the language. With a bottom up approach, you focus on looking for patterns within your code base (wether it is a single application or many) and look for efficient ways to describe the variability between different pieces of code so you can replace the custom code with some kind of higher level abstraction and some way of interpreting or generating the statements in that more concise language.
In general top down languages are more elegant and powerful but if you don't iterate between both approaches you may well end up with DSLs that are extremely hard to implement - especially if you're looking to integrate them in existing applications. As a general rule of thumb if you need a quick win or are re-factoring an existing code base you're going to want to focus more on bottom-up strategies and if you've got more time and/or a freer hand you may be able to invest more time in coming up with more powerful and elegant top down DSLs.
Once you've come up with a DSL, you can then look at alternative strategies for implementing it. DSL implementations are usually described as either in-language (where your DSL statements are written within your 3GL code) or external (where they are separate files which are only comprised of statements within your DSL). Let's look briefly at some common approaches:
In Language DSLs
In-language DSLs are usually implements via language extensions or APIs. The easiest way to implement a DSL in-language is to create a set of functions (or more likely these days classes with methods) where the method signatures define the API. These work well and are familiar to many programmers, but an API is only capable of expressing a subset of possible context free grammars - in short sometimes the syntax of n-sequential method calls isn't the ideal way to express a DSL.
The other way of implementing in-language DSLs is via language extensions. One of the reasons why Ruby has become popular recently is because it has a number of language features that make it easy to extend the core language. In ColdFusion the closest approximation would be creating custom tags that could be used to express statements within your DSLs, although for templates, you might be able to use Reg-ex replacements to implement certain DSLs.
Once you go outside of a language, you have a *lot* of options for expressing a DSL. Sure you could use XML (and it is often a good solution), but you could create a parser for your own custom syntax, you could allow people to draw diagrams to express statements or you could take spreadsheets or records in database tables as the concrete syntax for your DSLs.
The one thing most great programmers have in common is that they see themselves as language designers, building up layers of abstraction to allow them to more efficiently express their intent to solve a given problem or collection of problems (within or between projects). With the concepts of DSLs, we can all focus explicitly on doing a better job of emulating the best programmers to write efficient, maintainable code, and we can divorce the abstract grammars we design (the concepts, the attributes, their relationships and any constraints) from the concrete syntaxes we choose to implement them (anything from custom tags or XML to excel spreadsheets or method calls), allowing us to choose just the right grammars, constraints and syntaxes for our specific use cases.