DotNetSlackers: ASP.NET News for lazy Developers

Friday, January 7, 2011

Domain Specific Language using C# 4.0 - Part 2


In the first part of this article, we have seen the domain model and its usage for examination question paper as Level 0 in our step by step making of a DSL.

Level 1: Static Class and Method for Instantiation

Let us pick up the Exam constructor.
 Collapse
var dotnetExam = new Exam(".NET Fundamentals", Level.Beginner); 
In what way can we make this as domain-friendly.
  1. How the question preparer can know the first parameter is title of the exam, if he was provided with NotePad only? Forgot about API documentation et al. He is not a developer 
  2. Is it ok to have "var" and "new" keywords in this DSL?
To answer the first question, let us try to use C# "Named Argument" feature.
 Collapse
var dotExam = new Exam(title: ".NET Fundamentals", level: Level.Beginner);
Alternatively, when instantiating the Exam class, we can use the C# object initializer feature, if your domain allows this. When I'm designing the domain model for exam, I put constraints that Title and Level properties should be specified during instantiation. After that, these are only "get". And also, I hate to design domain objects with default constructor when business requires some constraints. For this case, if we relax this constraint, we can refactor the Exam as:
 Collapse
//Exam.cs
public string Title { get; set; }
public Level Level { get; set; }
public List<Question> Questions { get; private set; }

public Exam()
{
Question.QNo = 1;
Questions = new List<Question>();
}
and the instantiation would be:
 Collapse
var dotnetExam = new Exam { Title = ".NET Fundamentals", Level = Level.Beginner };
If we relax the rule of Exam object instantiation, we can use C# optional parameter in the constructor as:
 Collapse
//Exam.cs
public Exam(string title="Untitled", Level level = Level.Beginner)
{
Title = title;
        Level = level;
Question.QNo = 1;
Questions = new List<Question>();
} 
and the instantiation would be:
 Collapse
var dotnetExam = new Exam(title: ".NET Fundamentals");
Since, the one I'm preparing here is for beginners, I left the default option for Level.
We have almost answered the first question. However, how are we going to answer the second question. Avoid using "new", "var" C# keywords. Astatic factory method would be the option for this. Where can we create that method? In the Exam class itself or on a separate static class.Exam.create(...) wouldn't fit into the DSL. So, let us create a static class ExamBuilder.
 Collapse
//ExamBuilder.cs
public static class ExamBuilder
{
public static Exam exam(string title = "Untitled", Level level = Level.Beginner)
{
return new Exam() { Title = title, Level = level };
}
}
You may wonder why the method name violates the .NET method naming convention. Yes, I have violated it, after all, I'm going to create this DSL for a domain user, not for a .NET developer. Readability matters in DSL. See the usage of this:
 Collapse
var dotnetExam = ExamBuilder.exam(title: ".NET Fundamentals");
Still, "var" creates some noises in the DSL. But as of now, it is a required devil. Otherwise, how can we call Exam's AddQuestion() method.
But, why do we require intermediate variable "dotnetExam" here, because as a DSL, the user will add questions immediately after the "exam()" method. So, we can enforce:
 Collapse
ExamBuilder.exam(".NET Fundamentals").addQuestion(...);
But, how can we pass "question" objects to its "AddOption" method to add options and how can we create second, third, forth...n number of questions.
<a href="http://www.udooz.net/article/9-dsl/12-domain-specific-language-using-c-40-part-2.html" rel="tag" style="display:none">CodeProject</a>

No comments:

Post a Comment