How a Simple DSL Lets Non‑Developers Build Complex Surveys
This article explains the concept of domain‑specific languages (DSLs), compares internal and external DSLs, shows how to design a survey‑specific DSL with PEG.js, and discusses when using a DSL is worthwhile versus relying on existing tools.
Background and Problem Introduction (Tencent Survey Practice)
Creating a questionnaire often involves conditional logic, such as showing the second question only when the first answer meets certain criteria. Configuring this logic through the UI is time‑consuming, and complex requirements may require a developer to write custom code, leading to high communication overhead.
Researcher: Hey, can you develop a questionnaire? Developer: Tell me the requirements. Researcher: ... (detailed scenario) Developer: I don’t understand this part...
Because developers may lack domain knowledge and researchers lack coding skills, a gap emerges. A domain‑specific language (DSL) can bridge this gap, allowing researchers to define custom logic without developer assistance.
What is DSL
DSL stands for Domain Specific Language, a programming language designed for a particular domain. It can be thought of as a set of syntax rules to describe related behaviors. Low‑level examples include C++ or JavaScript; high‑level examples include Markdown for documents or SQL for database queries. DSLs are human‑oriented, unlike raw machine instructions.
Internal DSL and External DSL
Consider three ways to represent “two weeks ago”. The first is standard JavaScript code, the second resembles natural language, and the third is pseudo‑code. The second and third are external and internal DSLs respectively; external DSLs need a separate interpreter or compiler, while internal DSLs extend an existing host language.
new Date(Date.now() - 1000 * 60 * 60 * 24 * 7 * 2); 2 weeks ago (2).weeks().ago();Internal DSLs can be implemented by extending the host language, for example by adding methods to Number.prototype in JavaScript.
Number.prototype.weeks = function() { return this * 1000 * 60 * 60 * 24 * 7; };
Number.prototype.ago = function() { return new Date(Date.now() - this); };When to Use a DSL
A DSL is useful when the user is not a system developer but needs to customize logic, such as building complex questionnaires or custom database queries. Repetitive tasks, frequent multi‑party communication, and heavy GUI interaction are strong indicators for introducing a DSL.
Example: A Survey DSL
The questionnaire starts with Question 1 asking about fever. If the answer is “no fever”, it jumps to the end page; if “fever”, it shows Question 2. Question 2 asks for temperature, and if the temperature is below 37 °C, it also jumps to the end page.
Extracting the logical rules yields pseudo‑code:
if Q1A1 then branch to END
if Q1A2 then show Q2
if Q2A < 37 then branch to ENDFrom this we can design a simple DSL syntax:
if Q1A2 then show Q2
if Q2A gt 37 then show Q3Design Your DSL
Implementing a DSL follows the classic compilation pipeline: lexical analysis → syntax analysis → semantic analysis → AST generation → intermediate code → optimization → target code.
Lexical analysis → Syntax analysis → Semantic analysis → Generate AST → Intermediate code → Optimize → Generate target code
Instead of building a parser from scratch, you can use a parser generator such as PEG.js or Jison. Below is a PEG.js grammar that parses a single DSL statement like if Q1A2 then show Q2 and generates a JavaScript function.
const grammar = `
/* Define the input format: if xxx then xxx */
Start = 'if' _ exp:Expression _ 'then' _ op:Operation {
return new Function('questions', 'const result = [questions[0]];' +
'if(' + exp + ')' + op + 'return result;');
}
Expression "expression" = 'Q' q:[0-9] 'A' a:[0-9] {
return 'questions[' + q + '-1].answer === ' + a;
}
Operation "operation" = 'show Q' q:[0-9] {
return '{result.push(questions[' + q + '-1]);}';
}
_ "whitespace" = ' '
`;Install PEG.js with npm i pegjs, generate the parser via parser = pegjs.generate(grammar), and then parse DSL strings with parser.parse to obtain executable logic.
PEG.js also supports online parser generation, eliminating the need to install the library locally.
Don’t Use DSL Lightly
While DSLs are powerful, they require designing a syntax, building a parser, providing an editor, and writing documentation, all of which introduce learning overhead for users. Before adopting a DSL, ask whether an existing standard DSL or an internal DSL can meet the requirements.
If no better solution exists, then embrace the DSL.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
